diff --git a/.gitignore b/.gitignore index 4110018..476f58e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ /target/ /.classpath /bin/ +/bin/ diff --git a/CHANGELOG.md b/CHANGELOG.md index a6182d4..21afd80 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,18 +2,16 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm # Changelog for Common Smartgears -## [v3.1.6] +## [v4.0.0-SNAPSHOT] +- porting to keycloak + + +## [v3.2.0-SNAPSHOT] + +- Added SecretManagerProvider thread local from authorization-utils [#22871] - Added Linux distribution version [#22933] -## [v3.1.5] - 2022-04-20 - -- Added roles to ExternalService Info on request handler verification - -## [v3.1.4] - 2022-03-29 - -- fixes issue [#23075] - ## [v3.1.3] - 2022-03-21 - fixed bug on policies diff --git a/distro/smartgears-config.xml b/distro/smartgears-config.xml deleted file mode 100644 index ffa7124..0000000 --- a/distro/smartgears-config.xml +++ /dev/null @@ -1,2 +0,0 @@ - - \ No newline at end of file diff --git a/gcube/extra-resources/META-INF/smartgears-config.ini b/gcube/extra-resources/META-INF/smartgears-config.ini new file mode 100644 index 0000000..62fedff --- /dev/null +++ b/gcube/extra-resources/META-INF/smartgears-config.ini @@ -0,0 +1,2 @@ +[smartgears] +version = ${version} \ No newline at end of file diff --git a/pom.xml b/pom.xml index 2fbed7b..5d2e02e 100644 --- a/pom.xml +++ b/pom.xml @@ -8,39 +8,55 @@ 1.1.0 - org.gcube.core common-smartgears - 3.1.6 + 4.0.0-SNAPSHOT SmartGears - org.gcube.distribution gcube-bom - 2.1.0 + 3.0.0-SNAPSHOT pom import - distro - 7.0.42 - 1.17.1 + 8.0.42 + 2.25.1 UTF-8 + 11 + 11 - scm:git:https://code-repo.d4science.org/gCubeSystem/common-smartgears.git - scm:git:https://code-repo.d4science.org/gCubeSystem/common-smartgears.git + scm:git:httpstps://code-repo.d4science.org/gCubeSystem/common-smartgears.git https://code-repo.d4science.org/gCubeSystem/common-smartgears - - + + org.reflections + reflections + 0.9.10 + + + org.yaml + snakeyaml + 1.21 + + + io.github.classgraph + classgraph + 4.8.28 + + + org.gcube.common + health-api + 1.0.0-SNAPSHOT + org.gcube.common @@ -55,78 +71,59 @@ gcube-jackson-core - - org.gcube.common - authorization-client + common-security - - - org.gcube.common - common-authorization - - org.gcube.data.publishing document-store-lib - org.gcube.accounting accounting-lib - org.slf4j slf4j-api - - org.gcube.resources - registry-publisher + org.ini4j + ini4j + 0.5.4 - - - org.gcube.resources - common-gcore-resources - - org.gcube.core common-validator [1.0.0,2.0.0-SNAPSHOT) - - - org.gcube.core - common-scope - - org.gcube.core common-events [1.0.0,2.0.0-SNAPSHOT) - + + org.gcube.common.security + gcube-secrets + javax.servlet javax.servlet-api - 3.0.1 + 4.0.1 provided - - + - javax.xml.bind - jaxb-api - provided + io.micrometer + micrometer-core + 1.9.0 + + + io.micrometer + micrometer-registry-prometheus + 1.9.0 - - - - org.jboss.shrinkwrap.resolver shrinkwrap-resolver-depchain @@ -134,7 +131,6 @@ pom test - org.apache.tomcat @@ -142,67 +138,49 @@ ${tomcat.version} provided - org.apache.tomcat.embed tomcat-embed-core ${tomcat.version} test - - com.sun.jersey + org.glassfish.jersey.core jersey-client - ${jersey.version} + 2.25.1 test - - - - org.apache.tomcat.embed - tomcat-embed-core - ${tomcat.version} - test - - org.apache.tomcat.embed tomcat-embed-logging-log4j ${tomcat.version} test - org.apache.tomcat.embed tomcat-embed-jasper ${tomcat.version} test - junit junit 4.10 test - ch.qos.logback logback-classic runtime - org.mockito mockito-core 1.9.0 test - - - @@ -223,7 +201,18 @@ - + + org.apache.maven.plugins + maven-surefire-plugin + + + + projectVersion + ${project.version} + + + + org.apache.maven.plugins @@ -232,7 +221,6 @@ false probe - WEB-INF/classes/org/gcube/smartgears/probe/**/* false @@ -246,8 +234,6 @@ - - org.apache.maven.plugins maven-surefire-plugin @@ -277,9 +263,6 @@ ${distroDirectory} - - smartgears-config.xml - true @@ -287,7 +270,6 @@ - diff --git a/src/main/java/org/gcube/smartgears/Bootstrap.java b/src/main/java/org/gcube/smartgears/Bootstrap.java index 088f496..f1fa17f 100644 --- a/src/main/java/org/gcube/smartgears/Bootstrap.java +++ b/src/main/java/org/gcube/smartgears/Bootstrap.java @@ -14,6 +14,16 @@ 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; +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; +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. * @@ -76,6 +86,7 @@ public class Bootstrap implements ServletContainerInitializer { } // helpers + @SuppressWarnings("resource") private void initialiseContainer() { try { @@ -86,11 +97,24 @@ public class Bootstrap implements ServletContainerInitializer { /* Get the ContainerContext. Look at DefaultProvider */ context = ProviderFactory.provider().containerContext(); + PrometheusMeterRegistry registry = new PrometheusMeterRegistry(PrometheusConfig.DEFAULT); + + new ClassLoaderMetrics().bindTo(registry); + new JvmMemoryMetrics().bindTo(registry); + new JvmGcMetrics().bindTo(registry); + new ProcessorMetrics().bindTo(registry); + new JvmThreadMetrics().bindTo(registry); + new UptimeMetrics().bindTo(registry); + new ProcessorMetrics().bindTo(registry); + + Metrics.addRegistry(registry); + + /* Validate the configuration retrieved by ContainerContext * using gcube facilities annotation based * ( i.e org.gcube.common.validator.annotations) */ - //context.configuration().validate(); + context.configuration().validate(); } catch (RuntimeException e) { diff --git a/src/main/java/org/gcube/smartgears/Constants.java b/src/main/java/org/gcube/smartgears/Constants.java index fd4486b..e2df6f2 100644 --- a/src/main/java/org/gcube/smartgears/Constants.java +++ b/src/main/java/org/gcube/smartgears/Constants.java @@ -1,7 +1,7 @@ package org.gcube.smartgears; import org.gcube.smartgears.extensions.resource.RemoteResource; -import org.gcube.smartgears.handlers.application.lifecycle.ProfileManager; +import org.gcube.smartgears.handlers.application.request.RequestAccounting; import org.gcube.smartgears.handlers.application.request.RequestValidator; import org.gcube.smartgears.handlers.container.lifecycle.AccountingManager; @@ -27,8 +27,8 @@ public class Constants { /** * The container configuration file path, relative to the container configuration directory. - */ - public static final String container_configuraton_file_path = "container.xml"; + */ + public static final String container_configuraton_file_path = "container.ini"; /** @@ -36,25 +36,15 @@ public class Constants { */ public static final String container_profile_file_path = "ghn.xml"; + /* public static final String container_profile_file_path_copy = "ghn.xml.copy"; - - /** - * The container lifecycle configuration resource path. - */ - public static final String container_handlers_file_path = "/META-INF/container-handlers.xml"; - - public static final String container_handlers_file_name = "gcube-container-handlers.xml"; - - /** - * The library configuration resource path. - */ - public static final String library_configuration_file_path = "/META-INF/smartgears-config.xml"; + */ /** * The name of the context property that contains the node profile. - */ + public static final String container_profile_property = "ghn-profile"; - + */ /** * The default value of for the container publication frequency. @@ -62,24 +52,11 @@ public class Constants { public static final long default_container_publication_frequency_in_seconds = 60; - - /** * The application configuration resource path. */ - public static final String configuration_file_path = "/WEB-INF/gcube-app.xml"; + public static final String configuration_file_path = "/WEB-INF/application.yaml"; - /** - * The application lifecycle configuration resource path. - */ - public static final String handlers_file_path = "/WEB-INF/gcube-handlers.xml"; - - /** - * The default application lifecycle configuration resource path. - */ - public static final String default_handlers_file_path = "/META-INF/default-handlers.xml"; - - public static final String application_handlers_file_name = "gcube-application-handlers.xml"; /** * The wildcard exclude directive. @@ -92,16 +69,6 @@ public class Constants { */ public static final String root_mapping = "/gcube/resource"; - /** - * The application extensions configuration resource path. - */ - public static final String extensions_file_path = "/WEB-INF/gcube-extensions.xml"; - - /** - * The default application extensions configuration resource path. - */ - public static final String default_extensions_file_path = "/META-INF/default-extensions.xml"; - /** * The application frontpage resource path. */ @@ -117,6 +84,11 @@ public class Constants { */ public static final String request_validation = "request-validation"; + /** + * The configuration name of {@link RequestMetrics}s. + */ + public static final String request_metrics = "request-metrics"; + /** * The configuration name of {@link RequestValidator}s. */ @@ -140,8 +112,6 @@ public class Constants { public static final String remote_management = "remote-management"; - - /** * The path of the application profile file, relative to the service configuration directory. */ diff --git a/src/main/java/org/gcube/smartgears/configuration/AuthorizationProviderConfiguration.java b/src/main/java/org/gcube/smartgears/configuration/AuthorizationProviderConfiguration.java new file mode 100644 index 0000000..01cda29 --- /dev/null +++ b/src/main/java/org/gcube/smartgears/configuration/AuthorizationProviderConfiguration.java @@ -0,0 +1,37 @@ +package org.gcube.smartgears.configuration; + +import org.gcube.common.security.credentials.Credentials; +import org.gcube.common.validator.annotations.NotEmpty; +import org.gcube.common.validator.annotations.NotNull; +import org.gcube.smartgears.security.AuthorizationProviderFactory; + +public class AuthorizationProviderConfiguration { + + @NotNull @NotEmpty + AuthorizationProviderFactory authProviderFactory; + + @NotNull @NotEmpty + Credentials credentials; + + public AuthorizationProviderConfiguration(AuthorizationProviderFactory authProviderFactory, + Credentials credentials) { + super(); + this.authProviderFactory = authProviderFactory; + this.credentials = credentials; + } + + public AuthorizationProviderFactory getAuthProviderFactory() { + return authProviderFactory; + } + + public Credentials getCredentials() { + return credentials; + } + + @Override + public String toString() { + return "AuthorizationProviderConfiguration [authProviderFactory=" + authProviderFactory.getClass() + "]"; + } + + +} diff --git a/src/main/java/org/gcube/smartgears/configuration/ComponentConfiguration.java b/src/main/java/org/gcube/smartgears/configuration/ComponentConfiguration.java new file mode 100644 index 0000000..6c5f9da --- /dev/null +++ b/src/main/java/org/gcube/smartgears/configuration/ComponentConfiguration.java @@ -0,0 +1,10 @@ +package org.gcube.smartgears.configuration; + +import org.gcube.com.fasterxml.jackson.annotation.JsonTypeInfo; +import org.gcube.com.fasterxml.jackson.annotation.JsonTypeInfo.As; +import org.gcube.com.fasterxml.jackson.annotation.JsonTypeInfo.Id; + +@JsonTypeInfo(include=As.PROPERTY, use=Id.CLASS, property= "className") +public interface ComponentConfiguration { + +} diff --git a/src/main/java/org/gcube/smartgears/configuration/Configurable.java b/src/main/java/org/gcube/smartgears/configuration/Configurable.java new file mode 100644 index 0000000..9bfcb3c --- /dev/null +++ b/src/main/java/org/gcube/smartgears/configuration/Configurable.java @@ -0,0 +1,6 @@ +package org.gcube.smartgears.configuration; + +public interface Configurable { + + void configure(ComponentConfiguration configuration); +} diff --git a/src/main/java/org/gcube/smartgears/configuration/ConfiguredWith.java b/src/main/java/org/gcube/smartgears/configuration/ConfiguredWith.java new file mode 100644 index 0000000..be55a56 --- /dev/null +++ b/src/main/java/org/gcube/smartgears/configuration/ConfiguredWith.java @@ -0,0 +1,14 @@ +package org.gcube.smartgears.configuration; + +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +@Retention(RUNTIME) +@Target(ElementType.TYPE) +public @interface ConfiguredWith { + + public Class value(); +} diff --git a/src/main/java/org/gcube/smartgears/configuration/PersistenceConfiguration.java b/src/main/java/org/gcube/smartgears/configuration/PersistenceConfiguration.java new file mode 100644 index 0000000..3e42147 --- /dev/null +++ b/src/main/java/org/gcube/smartgears/configuration/PersistenceConfiguration.java @@ -0,0 +1,37 @@ +package org.gcube.smartgears.configuration; + +import org.gcube.com.fasterxml.jackson.annotation.JsonAutoDetect; +import org.gcube.com.fasterxml.jackson.annotation.JsonInclude; +import org.gcube.com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility; +import org.gcube.com.fasterxml.jackson.annotation.JsonInclude.Include; +import org.gcube.common.validator.annotations.IsValid; +import org.gcube.common.validator.annotations.NotNull; +import org.gcube.smartgears.persistence.PersistenceWriter; + +@JsonInclude(value = Include.NON_NULL) +@JsonAutoDetect(fieldVisibility = Visibility.ANY) +public class PersistenceConfiguration { + + @NotNull + private Class implementationClass; + + @IsValid + private ComponentConfiguration writerConfiguration; + + protected PersistenceConfiguration() {} + + public PersistenceConfiguration(Class implementationClass, T writerConfiguration) { + super(); + this.implementationClass = implementationClass; + this.writerConfiguration = writerConfiguration; + } + + public Class getImplementationClass() { + return this.implementationClass; + } + + public ComponentConfiguration getWriterConfiguration() { + return writerConfiguration; + } + +} diff --git a/src/main/java/org/gcube/smartgears/configuration/ProxyAddress.java b/src/main/java/org/gcube/smartgears/configuration/ProxyAddress.java new file mode 100644 index 0000000..731b20c --- /dev/null +++ b/src/main/java/org/gcube/smartgears/configuration/ProxyAddress.java @@ -0,0 +1,42 @@ +package org.gcube.smartgears.configuration; + +import org.gcube.common.validator.annotations.NotEmpty; +import org.gcube.common.validator.annotations.NotNull; + +public class ProxyAddress { + + @NotNull @NotEmpty + String protocol = "http"; + + @NotNull @NotEmpty + String hostname; + + @NotNull + Integer port; + + public String getProtocol() { + return protocol; + } + + public void setProtocol(String protocol) { + this.protocol = protocol; + } + + public String getHostname() { + return hostname; + } + + public void setHostname(String hostname) { + this.hostname = hostname; + } + + public Integer getPort() { + return port; + } + + public void setPort(Integer port) { + this.port = port; + } + + +} diff --git a/src/main/java/org/gcube/smartgears/configuration/SmartgearsConfiguration.java b/src/main/java/org/gcube/smartgears/configuration/SmartgearsConfiguration.java new file mode 100644 index 0000000..43d6311 --- /dev/null +++ b/src/main/java/org/gcube/smartgears/configuration/SmartgearsConfiguration.java @@ -0,0 +1,15 @@ +package org.gcube.smartgears.configuration; + +public class SmartgearsConfiguration { + + private String version; + + public SmartgearsConfiguration(String version) { + super(); + this.version = version; + } + + public String getVersion() { + return version; + } +} diff --git a/src/main/java/org/gcube/smartgears/configuration/application/ApplicationConfiguration.java b/src/main/java/org/gcube/smartgears/configuration/application/ApplicationConfiguration.java index c7e1257..8f46c9d 100644 --- a/src/main/java/org/gcube/smartgears/configuration/application/ApplicationConfiguration.java +++ b/src/main/java/org/gcube/smartgears/configuration/application/ApplicationConfiguration.java @@ -1,167 +1,182 @@ package org.gcube.smartgears.configuration.application; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Objects; import java.util.Set; -import org.gcube.smartgears.configuration.Mode; -import org.gcube.smartgears.persistence.Persistence; +import org.gcube.com.fasterxml.jackson.annotation.JsonAutoDetect; +import org.gcube.com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility; +import org.gcube.com.fasterxml.jackson.annotation.JsonIgnore; +import org.gcube.com.fasterxml.jackson.annotation.JsonInclude; +import org.gcube.com.fasterxml.jackson.annotation.JsonInclude.Include; +import org.gcube.com.fasterxml.jackson.annotation.JsonProperty; +import org.gcube.common.validator.ValidationError; +import org.gcube.common.validator.Validator; +import org.gcube.common.validator.ValidatorFactory; +import org.gcube.common.validator.annotations.NotEmpty; +import org.gcube.common.validator.annotations.NotNull; +import org.gcube.smartgears.configuration.PersistenceConfiguration; /** - * The configuration of the application. - * - * @author Fabio Simeoni + * The configuration of a managed app. + *

+ * Includes the list of its client services. + * + * @author Lucio Lelii * */ -public interface ApplicationConfiguration { +@JsonInclude(value = Include.NON_NULL) +@JsonAutoDetect(fieldVisibility = Visibility.ANY) +public class ApplicationConfiguration { + + @NotNull + String name; + + @NotNull + String group; + + @NotNull + String version; + + String description=""; + + @JsonIgnore + String context; + + private boolean proxable = true; + + Set excludes= new HashSet<>(); + + Set includes= new HashSet<>(); + + @NotEmpty @JsonProperty("persistence") + PersistenceConfiguration persistenceConfiguration; + + public Set excludes() { + return excludes; + } + + public Set includes() { + return includes; + } + + public ApplicationConfiguration() {} + + public String name() { + return name; + } + + public String context() { + return context; + } + + public ApplicationConfiguration excludes(GCubeExclude ... excludes) { + this.excludes=new HashSet(Arrays.asList(excludes)); + return this; + } + + public ApplicationConfiguration includes(GCubeInclude... includes) { + this.includes=new HashSet(Arrays.asList(includes)); + return this; + } + + public ApplicationConfiguration context(String context) { + this.context = context; + return this; + } + + public ApplicationConfiguration name(String name) { + this.name=name; + return this; + } + + public ApplicationConfiguration persistenceConfiguration(PersistenceConfiguration configuration) { + this.persistenceConfiguration = configuration; + return this; + } + + public ApplicationConfiguration proxable(boolean proxable) { + this.proxable = proxable; + return this; + } + + public String group() { + return group; + } + + + public ApplicationConfiguration group(String group) { + this.group=group; + return this; + } + + public String version() { + return version; + } + + public ApplicationConfiguration version(String version) { + this.version=version; + return this; + } - /** - * Returns the management mode of the application. - * @return the management mode - */ - Mode mode(); + public String description() { + return description; + } - - - /** - * Returns the context path of the application - * @return the context path - */ - String context(); - - boolean proxied(); - - /** - * Sets the context path of the application - * @param context the context path - * @return this configuration - */ - ApplicationConfiguration context(String context); - - /** - * Sets the management mode of this application. - * @param the management mode - * @return this configuration - */ - ApplicationConfiguration mode(Mode mode); - - - /** - * Returns the name of the application. - * @return the name - */ - String name(); - - - /** - * Sets the name of the application. - * @param name the name - * @return this configuration - */ - ApplicationConfiguration name(String name); + public ApplicationConfiguration description(String description) { + this.description=description; + return this; + } - /** - * Returns the class of the application - * @return the class - */ - String serviceClass(); + public boolean proxable() { + return proxable; + } + + public PersistenceConfiguration persistenceConfiguration() { + return persistenceConfiguration; + } + + public void validate() { + + List msgs = new ArrayList(); + + Validator validator = ValidatorFactory.validator(); + + for (ValidationError error : validator.validate(this)) + msgs.add(error.toString()); + + if (!this.excludes().isEmpty() && !this.includes().isEmpty()) + msgs.add("exclude tags and includes tags are mutually exclusive"); + + if (!msgs.isEmpty()) + throw new IllegalStateException("invalid configuration: "+msgs); + + } - /** - * Sets the class of the application. - * @param serviceClass the class - * @return this configuration - */ - ApplicationConfiguration serviceClass(String serviceClass); + @Override + public int hashCode() { + return Objects.hash(description, excludes, group, includes, name, proxable, version); + } - /** - * Returns the version of the application. - * @return the version - */ - String version(); - - /** - * Sets the version of the application. - * @param version the version - * @return this configuration - */ - ApplicationConfiguration version(String version); - - /** - * Returns the description of the application. - * @return the description - */ - String description(); - - /** - * Sets the description of the application. - * @param description the description - * @return this configuration - */ - ApplicationConfiguration description(String description); - - ProxyAddress proxyAddress(); - - ApplicationConfiguration proxyAddress(ProxyAddress proxyaddress); - - /** - * Returns the tokens in which the application operates when it first starts. - * @return the tokens - */ - Set startTokens(); - - /** - * Sets the tokens in which the application operates when it first starts. - * @param scopes the scopes - * @return this configuration - */ - ApplicationConfiguration startTokens(Set tokens); + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + ApplicationConfiguration other = (ApplicationConfiguration) obj; + return Objects.equals(description, other.description) + && Objects.equals(excludes, other.excludes) && Objects.equals(group, other.group) + && Objects.equals(includes, other.includes) && Objects.equals(name, other.name) + && proxable == other.proxable && Objects.equals(version, other.version); + } - /** - * Returns the persistence manager of the application. - * @return the manager - */ - Persistence persistence(); - - /** - * Returns a set of request paths that should not be subjected to request management. - * @return the set of exclude paths. - */ - Set excludes(); - - /** - * Returns a set of request paths that should be subjected to request management. - * @return the set of exclude paths. - */ - Set includes(); - - - /** - * Sets the persistence manager of the application. - * @param manager the manager - * @return this configuration - */ - ApplicationConfiguration persistence(Persistence manager); - - - /** - * Validates this configuration. - * - * @throws IllegalStateException if the configuration is not valid - */ - void validate(); - - - /** - * Merges this configuration with another configuration - * @param config the other configuration - */ - void merge(ApplicationConfiguration config); - - ApplicationConfiguration excludes(Exclude ... excludes); - - ApplicationConfiguration includes(Include ... includes); - - - } \ No newline at end of file diff --git a/src/main/java/org/gcube/smartgears/configuration/application/ApplicationConfigurationBinder.java b/src/main/java/org/gcube/smartgears/configuration/application/ApplicationConfigurationBinder.java index 9a81583..f7699a1 100644 --- a/src/main/java/org/gcube/smartgears/configuration/application/ApplicationConfigurationBinder.java +++ b/src/main/java/org/gcube/smartgears/configuration/application/ApplicationConfigurationBinder.java @@ -1,18 +1,22 @@ package org.gcube.smartgears.configuration.application; -import static org.gcube.smartgears.utils.Utils.*; - +import java.io.File; import java.io.InputStream; -import java.lang.reflect.Modifier; -import java.util.HashSet; -import java.util.ServiceLoader; -import java.util.Set; +import java.util.LinkedList; +import java.util.List; -import javax.xml.bind.JAXBContext; -import javax.xml.bind.JAXBException; - -import org.gcube.smartgears.extensions.ApplicationExtension; -import org.gcube.smartgears.handlers.application.ApplicationHandler; +import org.gcube.com.fasterxml.jackson.databind.ObjectMapper; +import org.gcube.smartgears.configuration.PersistenceConfiguration; +import org.gcube.smartgears.handlers.application.ApplicationLifecycleHandler; +import org.gcube.smartgears.handlers.application.RequestHandler; +import org.gcube.smartgears.handlers.application.lifecycle.ApplicationProfileManager; +import org.gcube.smartgears.handlers.application.request.RequestAccounting; +import org.gcube.smartgears.handlers.application.request.RequestMetrics; +import org.gcube.smartgears.handlers.application.request.RequestValidator; +import org.gcube.smartgears.persistence.LocalWriter; +import org.gcube.smartgears.persistence.LocalWriterConfiguration; +import org.gcube.smartgears.utils.Utils; +import org.yaml.snakeyaml.Yaml; /** * Binds {@link ApplicationConfiguration}s to and from XML serialisations. @@ -29,21 +33,28 @@ public class ApplicationConfigurationBinder { * @return the configuration * @throws RuntimeException if the serialisation is invalid */ - public ApplicationConfiguration bind(InputStream stream) { - + public ApplicationConfiguration load(InputStream stream) { try { + Yaml yaml = new Yaml(); + ObjectMapper mapper = new ObjectMapper(); + String mapAsString = mapper.writeValueAsString(yaml.load(stream)); - JAXBContext ctx = JAXBContext.newInstance(DefaultApplicationConfiguration.class); + ApplicationConfiguration conf = mapper.readValue(mapAsString, ApplicationConfiguration.class); - return (ApplicationConfiguration) ctx.createUnmarshaller().unmarshal(stream); + if (conf.persistenceConfiguration() == null) { + String location = String.format("%s/state/%s_%s", Utils.home(), conf.group(), conf.name()); + File dir = new File(location); + if (!dir.exists()) + dir.mkdirs(); - } catch (JAXBException e) { + conf.persistenceConfiguration( + new PersistenceConfiguration(LocalWriter.class, new LocalWriterConfiguration(location))); - throw new RuntimeException("invalid service configuration", e); + } - } - finally { - closeSafely(stream); + return conf; + } catch (Exception e) { + throw new RuntimeException(e); } } @@ -54,96 +65,82 @@ public class ApplicationConfigurationBinder { * @return the handlers * @throws RuntimeException if the serialisation is invalid */ - public ApplicationHandlers bindHandlers(InputStream stream) { + public ApplicationHandlers bindHandlers(ClassLoader classLoader) { - //collects handler classes - Set> classes = scanForHandlers(); + List requestHandlers = new LinkedList(); - try { + // ADDING BASE Handler (order is important) + requestHandlers.add(new RequestMetrics()); + requestHandlers.add(new RequestValidator()); + requestHandlers.add(new RequestAccounting()); - JAXBContext ctx = JAXBContext.newInstance(classes.toArray(new Class[0])); + // TODO scan RequestHAndler form classloader - return (ApplicationHandlers) ctx.createUnmarshaller().unmarshal(stream); + List lifecycleHandlers = new LinkedList(); - } catch (JAXBException e) { + // ADDING BASE Handler (order is important) + lifecycleHandlers.add(new ApplicationProfileManager()); - throw unchecked(e); + // TODO scan ApplicationLifecycleHandler form classloader + + return new ApplicationHandlers(lifecycleHandlers, requestHandlers); - } - finally { - closeSafely(stream); - } } - + /** * Returns the extensions of the application from their XML serialisation. * * @param stream the serialisation * @return the extensions * @throws RuntimeException if the serialisation is invalid + * + * public ApplicationExtensions + * bindExtensions(InputStream stream) { + * + * //collects handler classes Set> classes = + * scanForExtensions(); + * + * try { + * + * JAXBContext ctx = + * JAXBContext.newInstance(classes.toArray(new + * Class[0])); + * + * return (ApplicationExtensions) + * ctx.createUnmarshaller().unmarshal(stream); + * + * } catch (JAXBException e) { + * + * throw unchecked(e); + * + * } finally { closeSafely(stream); } } + * + * + * + * private Set> scanForExtensions() throws + * RuntimeException { + * + * @SuppressWarnings("all") + * ServiceLoader handlerLoader = + * (ServiceLoader) + * ServiceLoader.load(ApplicationExtension.class); + * + * Set> scanned = new HashSet>(); + * + * for (ApplicationExtension handler : handlerLoader) { + * Class handlerClass = handler.getClass(); if + * (handlerClass.isInterface() || + * handlerClass.getModifiers() == Modifier.ABSTRACT) + * continue; else scanned.add(handlerClass); } + * + * //add top-level configuration + * scanned.add(ApplicationExtensions.class); + * + * return scanned; } */ - public ApplicationExtensions bindExtensions(InputStream stream) { - //collects handler classes - Set> classes = scanForExtensions(); - - try { - - JAXBContext ctx = JAXBContext.newInstance(classes.toArray(new Class[0])); - - return (ApplicationExtensions) ctx.createUnmarshaller().unmarshal(stream); - - } catch (JAXBException e) { - - throw unchecked(e); - - } - finally { - closeSafely(stream); - } + public void scanForApplicationHandlers(ClassLoader currentClassLoader) { + // TODO Auto-generated method stub } - - - - private Set> scanForHandlers() throws RuntimeException { - @SuppressWarnings("all") - ServiceLoader handlerLoader = (ServiceLoader) ServiceLoader.load(ApplicationHandler.class); - - Set> scanned = new HashSet>(); - - for (ApplicationHandler handler : handlerLoader) { - Class handlerClass = handler.getClass(); - if (handlerClass.isInterface() || handlerClass.getModifiers() == Modifier.ABSTRACT) - continue; - else - scanned.add(handlerClass); - } - - //add top-level configuration - scanned.add(ApplicationHandlers.class); - - return scanned; - } - - private Set> scanForExtensions() throws RuntimeException { - - @SuppressWarnings("all") - ServiceLoader handlerLoader = (ServiceLoader) ServiceLoader.load(ApplicationExtension.class); - - Set> scanned = new HashSet>(); - - for (ApplicationExtension handler : handlerLoader) { - Class handlerClass = handler.getClass(); - if (handlerClass.isInterface() || handlerClass.getModifiers() == Modifier.ABSTRACT) - continue; - else - scanned.add(handlerClass); - } - - //add top-level configuration - scanned.add(ApplicationExtensions.class); - - return scanned; - } } diff --git a/src/main/java/org/gcube/smartgears/configuration/application/ApplicationExtensions.java b/src/main/java/org/gcube/smartgears/configuration/application/ApplicationExtensions.java deleted file mode 100644 index 53496de..0000000 --- a/src/main/java/org/gcube/smartgears/configuration/application/ApplicationExtensions.java +++ /dev/null @@ -1,75 +0,0 @@ -package org.gcube.smartgears.configuration.application; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import javax.xml.bind.Unmarshaller; -import javax.xml.bind.annotation.XmlAnyElement; -import javax.xml.bind.annotation.XmlRootElement; - -import org.gcube.common.validator.ValidationError; -import org.gcube.common.validator.Validator; -import org.gcube.common.validator.ValidatorFactory; -import org.gcube.common.validator.annotations.IsValid; -import org.gcube.smartgears.extensions.ApplicationExtension; -import org.w3c.dom.Element; - -/** - * The {@link ApplicationExtension}s that manage the application. - * - * @author Fabio Simeoni - * - */ -@XmlRootElement(name="extensions") -public class ApplicationExtensions { - - @XmlAnyElement(lax=true) @IsValid - List extensions = new ArrayList(); - - public ApplicationExtensions() {} - - /** - * Returns the extensions for the application. - * @return the extensions - */ - public List extensions() { - return extensions; - } - - /** - * Sets the extensions for the application. - * @param extensions the extensions - * @return this configuration - */ - public ApplicationExtensions set(ApplicationExtension ... extensions) { - this.extensions = Arrays.asList(extensions); - return this; - } - - @Override - public String toString() { - return extensions.toString(); - } - - public void validate() { - - List msgs = new ArrayList(); - - Validator validator = ValidatorFactory.validator(); - - for (ValidationError error : validator.validate(this)) - msgs.add(error.toString()); - - if (!msgs.isEmpty()) - throw new IllegalStateException("invalid configuration: "+msgs); - - } - - //since we use @AnyElement, after deserialisation, we check there are no DOM elements - void afterUnmarshal(Unmarshaller u, Object parent) { - for (Object o : extensions) - if (o instanceof Element) - throw new RuntimeException("invalid extensions detected: "+Element.class.cast(o).getLocalName()); - } - -} \ No newline at end of file diff --git a/src/main/java/org/gcube/smartgears/configuration/application/ApplicationHandlers.java b/src/main/java/org/gcube/smartgears/configuration/application/ApplicationHandlers.java index a0c553c..eade558 100644 --- a/src/main/java/org/gcube/smartgears/configuration/application/ApplicationHandlers.java +++ b/src/main/java/org/gcube/smartgears/configuration/application/ApplicationHandlers.java @@ -1,21 +1,11 @@ package org.gcube.smartgears.configuration.application; -import java.util.ArrayList; -import java.util.Arrays; +import java.util.LinkedList; import java.util.List; -import javax.xml.bind.Unmarshaller; -import javax.xml.bind.annotation.XmlAnyElement; -import javax.xml.bind.annotation.XmlElement; -import javax.xml.bind.annotation.XmlRootElement; -import org.gcube.common.validator.ValidationError; -import org.gcube.common.validator.Validator; -import org.gcube.common.validator.ValidatorFactory; -import org.gcube.common.validator.annotations.IsValid; import org.gcube.smartgears.handlers.application.ApplicationHandler; import org.gcube.smartgears.handlers.application.ApplicationLifecycleHandler; import org.gcube.smartgears.handlers.application.RequestHandler; -import org.w3c.dom.Element; /** * The {@link ApplicationHandler}s that manage the application. @@ -23,24 +13,24 @@ import org.w3c.dom.Element; * @author Fabio Simeoni * */ -@XmlRootElement(name="handlers") public class ApplicationHandlers { - @XmlElement(name="lifecycle") @IsValid - private LifecycleHandlers lifecycleHandlers = new LifecycleHandlers(); + private List lifecycleHandlers = new LinkedList(); - @XmlElement(name="request") @IsValid - private RequestHandlers requestHandlers = new RequestHandlers(); + private List requestHandlers = new LinkedList(); - public ApplicationHandlers() {} + public ApplicationHandlers(List lifecycleHandlers, List requestHandlers) { + this.lifecycleHandlers = lifecycleHandlers; + this.requestHandlers = requestHandlers; + } /** * Returns the {@link ApplicationLifecycleHandler}s for the service. * @return the lifecycle handlers */ public List lifecycleHandlers() { - return lifecycleHandlers.values; + return lifecycleHandlers; } /** @@ -48,8 +38,8 @@ public class ApplicationHandlers { * @param handlers the lifecycle handlers * @return this configuration */ - public ApplicationHandlers set(ApplicationLifecycleHandler ... handlers) { - this.lifecycleHandlers = new LifecycleHandlers(Arrays.asList(handlers)); + public ApplicationHandlers setLifecycleHandlers(List handlers) { + this.lifecycleHandlers = handlers; return this; } @@ -58,7 +48,7 @@ public class ApplicationHandlers { * @return the lifetime handlers */ public List requestHandlers() { - return requestHandlers.values; + return requestHandlers; } /** @@ -66,75 +56,11 @@ public class ApplicationHandlers { * @param handlers the request handlers * @return this configuration */ - public ApplicationHandlers set(RequestHandler ... handlers) { - this.requestHandlers = new RequestHandlers(Arrays.asList(handlers)); + public ApplicationHandlers setRequetHandlers(List handlers) { + this.requestHandlers = handlers; return this; } - - public void validate() { - - List msgs = new ArrayList(); - - Validator validator = ValidatorFactory.validator(); - - for (ValidationError error : validator.validate(this)) - msgs.add(error.toString()); - - if (!msgs.isEmpty()) - throw new IllegalStateException("invalid configuration: "+msgs); - - } - - //////////////// HELPER BINDING CLASSES - - //used internally to introduce level of nesting in JAXB whilst preserving arbitrary extension - - private static class LifecycleHandlers { - - @SuppressWarnings("all") - LifecycleHandlers() { //needed for deserialisation - } - - LifecycleHandlers(List handlers) { - this.values=handlers; - } - - @XmlAnyElement(lax=true) - List values = new ArrayList(); - - - //since we use @AnyElement, after deserialisation, we check there are no DOM elements - @SuppressWarnings("unused") - void afterUnmarshal(Unmarshaller u, Object parent) { - for (Object o : values) - if (o instanceof Element) - throw new RuntimeException("invalid handler detected in configuration: "+Element.class.cast(o).getLocalName()); - } - - } - - //used internally to introduce level of nesting in JAXB whilst preserving arbitrary extension - private static class RequestHandlers { - - @SuppressWarnings("all") - RequestHandlers() { //needed for deserialisation - } - - RequestHandlers(List handlers) { - this.values=handlers; - } - - @XmlAnyElement(lax=true) - List values = new ArrayList(); - - //since we use @AnyElement, after deserialisation, we check there are no DOM elements - @SuppressWarnings("unused") - void afterUnmarshal(Unmarshaller u, Object parent) { - for (Object o : values) - if (o instanceof Element) - throw new RuntimeException("invalid handler detected in configuration: "+Element.class.cast(o).getLocalName()); - } - } + public void mergeWith(ApplicationHandlers other){ List lifecycles = other.lifecycleHandlers(); diff --git a/src/main/java/org/gcube/smartgears/configuration/application/BridgedApplicationConfiguration.java b/src/main/java/org/gcube/smartgears/configuration/application/BridgedApplicationConfiguration.java deleted file mode 100644 index caa3de1..0000000 --- a/src/main/java/org/gcube/smartgears/configuration/application/BridgedApplicationConfiguration.java +++ /dev/null @@ -1,167 +0,0 @@ -package org.gcube.smartgears.configuration.application; - -import static org.gcube.smartgears.configuration.Mode.offline; - -import java.io.File; -import java.util.Set; - -import org.gcube.smartgears.configuration.Mode; -import org.gcube.smartgears.configuration.container.ContainerConfiguration; -import org.gcube.smartgears.persistence.DefaultPersistence; -import org.gcube.smartgears.persistence.Persistence; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * - * @author Fabio Simeoni - * @author Luca Frosini (ISTI - CNR) - */ -public class BridgedApplicationConfiguration implements ApplicationConfiguration { - - private static Logger log = LoggerFactory.getLogger(ApplicationConfiguration.class); - - private final ContainerConfiguration container; - private final ApplicationConfiguration application; - - - public BridgedApplicationConfiguration(ContainerConfiguration container, ApplicationConfiguration config) { - - this.container=container; - this.application=config; - - if (application.persistence()==null) { - - String location = container.persistence().location()+"/"+application.name(); - File dir = new File(location); - if (!dir.exists()) - dir.mkdirs(); - - application.persistence(new DefaultPersistence(location)); - - log.trace("setting persistence location for {} @ {}",application.name(), dir.getAbsolutePath()); - } - - } - - public ApplicationConfiguration inner() { - return application; - } - - public Mode mode() { - return container.mode()==offline?offline:application.mode(); - } - - @Override - public String context() { - return application.context(); - } - - @Override - public ApplicationConfiguration context(String context) { - return application.context(context); - } - - public String name() { - return application.name(); - } - - public ApplicationConfiguration name(String name) { - return application.name(name); - } - - public String serviceClass() { - return application.serviceClass(); - } - - public ApplicationConfiguration serviceClass(String group) { - return application.serviceClass(group); - } - - public String version() { - return application.version(); - } - - public ApplicationConfiguration version(String version) { - return application.version(version); - } - - public String description() { - return application.description(); - } - - public ProxyAddress proxyAddress() { - return application.proxyAddress(); - } - - public ApplicationConfiguration description(String description) { - return application.description(description); - } - - public Persistence persistence() { - return application.persistence(); - } - - public ApplicationConfiguration persistence(Persistence manager) { - return application.persistence(manager); - } - - public ApplicationConfiguration mode(Mode mode) { - return application.mode(mode); - } - - public void validate() { - - application.validate(); - - } - - @Override - public Set excludes() { - return application.excludes(); - } - - @Override - public Set includes() { - return application.includes(); - } - - @Override - public void merge(ApplicationConfiguration config) { - application.merge(config); - } - - - @Override - public Set startTokens() { - return application.startTokens(); - } - - @Override - public ApplicationConfiguration startTokens(Set tokens) { - return application.startTokens(tokens); - } - - - @Override - public boolean proxied() { - return application.proxied(); - } - - @Override - public ApplicationConfiguration excludes(Exclude ... excludes) { - return application.excludes(excludes); - } - - @Override - public ApplicationConfiguration includes(Include... includes) { - return application.includes(includes); - } - - @Override - public ApplicationConfiguration proxyAddress(ProxyAddress proxyaddress) { - return application.proxyAddress(proxyaddress); - } - - -} diff --git a/src/main/java/org/gcube/smartgears/configuration/application/DefaultApplicationConfiguration.java b/src/main/java/org/gcube/smartgears/configuration/application/DefaultApplicationConfiguration.java deleted file mode 100644 index a4fe514..0000000 --- a/src/main/java/org/gcube/smartgears/configuration/application/DefaultApplicationConfiguration.java +++ /dev/null @@ -1,237 +0,0 @@ -package org.gcube.smartgears.configuration.application; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashSet; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Set; - -import javax.xml.bind.annotation.XmlAttribute; -import javax.xml.bind.annotation.XmlElement; -import javax.xml.bind.annotation.XmlElementRef; -import javax.xml.bind.annotation.XmlRootElement; -import javax.xml.bind.annotation.XmlTransient; - -import org.gcube.common.validator.ValidationError; -import org.gcube.common.validator.Validator; -import org.gcube.common.validator.ValidatorFactory; -import org.gcube.common.validator.annotations.IsValid; -import org.gcube.common.validator.annotations.NotNull; -import org.gcube.smartgears.configuration.Mode; -import org.gcube.smartgears.persistence.DefaultPersistence; -import org.gcube.smartgears.persistence.Persistence; - -/** - * The configuration of a managed app. - *

- * Includes the list of its client services. - * - * @author Fabio Simeoni - * @author Luca Frosini (ISTI - CNR) - * - */ -@XmlRootElement(name="application") -public class DefaultApplicationConfiguration implements ApplicationConfiguration { - - - @XmlAttribute - private Mode mode = Mode.online; - - @XmlAttribute(name="context") - String context; - - @XmlElement(name="name" , required=true) - @NotNull - String name; - - @XmlElement(name="group", required=true) - @NotNull - String group; - - @XmlElement(name="version", required=true) - @NotNull - String version; - - @XmlTransient - Set tokens = new HashSet(); - - @XmlElement(name="description") - String description=""; - - @XmlElementRef - @IsValid - ProxyAddress proxyAddress; - - @XmlElementRef - Set excludes= new LinkedHashSet(); - - @XmlElementRef - Set includes= new LinkedHashSet(); - - @XmlElementRef(type=DefaultPersistence.class) - @NotNull @IsValid - private Persistence persistenceManager; - - @Override - public Set excludes() { - return excludes; - } - - - @Override - public Set includes() { - return includes; - } - - public DefaultApplicationConfiguration() {} - - @Override - public Mode mode() { - return mode; - } - - @Override - public String name() { - return name; - } - - @Override - public String context() { - return context; - } - - @Override - public ApplicationConfiguration context(String context) { - this.context=context; - return this; - } - - public ProxyAddress proxyAddress() { - return proxyAddress; - } - - @Override - public ApplicationConfiguration excludes(Exclude ... excludes) { - this.excludes=new HashSet(Arrays.asList(excludes)); - return this; - } - - @Override - public ApplicationConfiguration includes(Include... includes) { - this.includes=new HashSet(Arrays.asList(includes)); - return this; - } - - @Override - public ApplicationConfiguration name(String name) { - this.name=name; - return this; - } - - @Override - public String serviceClass() { - return group; - } - - - @Override - public ApplicationConfiguration serviceClass(String group) { - this.group=group; - return this; - } - - @Override - public String version() { - return version; - } - - @Override - public ApplicationConfiguration version(String version) { - this.version=version; - return this; - } - - @Override - public Set startTokens() { - return tokens; - } - - @Override - public ApplicationConfiguration startTokens(Set tokens) { - this.tokens.addAll(tokens); - return this; - } - - @Override - public String description() { - return description; - } - - @Override - public ApplicationConfiguration description(String description) { - this.description=description; - return this; - } - - @Override - public boolean proxied() { - return proxyAddress!=null; - } - - @Override - public Persistence persistence() { - return persistenceManager; - } - - @Override - public ApplicationConfiguration persistence(Persistence manager) { - this.persistenceManager=manager; - return this; - } - - @Override - public ApplicationConfiguration proxyAddress(ProxyAddress proxyaddress) { - this.proxyAddress = proxyaddress; - return this; - } - - @Override - public ApplicationConfiguration mode(Mode mode) { - this.mode=mode; - return this; - } - - @Override - public void validate() { - - List msgs = new ArrayList(); - - Validator validator = ValidatorFactory.validator(); - - for (ValidationError error : validator.validate(this)) - msgs.add(error.toString()); - - if (!this.excludes().isEmpty() && !this.includes().isEmpty()) - msgs.add("exclude tags and includes tags are mutually exclusive"); - - if (!msgs.isEmpty()) - throw new IllegalStateException("invalid configuration: "+msgs); - - } - - - @Override - public void merge(ApplicationConfiguration config) { - - mode(config.mode()); - - if (config.persistence()!=null) - persistence(config.persistence()); - - //scopes.addAll(config.startScopes()); - - } - - -} \ No newline at end of file diff --git a/src/main/java/org/gcube/smartgears/configuration/application/Exclude.java b/src/main/java/org/gcube/smartgears/configuration/application/GCubeExclude.java similarity index 68% rename from src/main/java/org/gcube/smartgears/configuration/application/Exclude.java rename to src/main/java/org/gcube/smartgears/configuration/application/GCubeExclude.java index 579758b..264500b 100644 --- a/src/main/java/org/gcube/smartgears/configuration/application/Exclude.java +++ b/src/main/java/org/gcube/smartgears/configuration/application/GCubeExclude.java @@ -3,20 +3,14 @@ package org.gcube.smartgears.configuration.application; import java.util.ArrayList; import java.util.List; -import javax.xml.bind.annotation.XmlAccessType; -import javax.xml.bind.annotation.XmlAccessorType; -import javax.xml.bind.annotation.XmlAttribute; -import javax.xml.bind.annotation.XmlRootElement; -import javax.xml.bind.annotation.XmlValue; +import org.gcube.common.validator.annotations.NotEmpty; -@XmlRootElement(name="exclude") -@XmlAccessorType(XmlAccessType.FIELD) -public class Exclude { +public class GCubeExclude { - @XmlAttribute(name="handlers") + @NotEmpty private List handlers = new ArrayList(); - @XmlValue + @NotEmpty private String path; public List getHandlers() { @@ -27,14 +21,14 @@ public class Exclude { return path; } - protected Exclude() {} + protected GCubeExclude() {} - public Exclude(String path) { + public GCubeExclude(String path) { super(); this.path = path; } - public Exclude(List handlers, String path) { + public GCubeExclude(List handlers, String path) { super(); this.handlers = handlers; this.path = path; @@ -57,7 +51,7 @@ public class Exclude { return false; if (getClass() != obj.getClass()) return false; - Exclude other = (Exclude) obj; + GCubeExclude other = (GCubeExclude) obj; if (handlers == null) { if (other.handlers != null) return false; diff --git a/src/main/java/org/gcube/smartgears/configuration/application/Include.java b/src/main/java/org/gcube/smartgears/configuration/application/GCubeInclude.java similarity index 69% rename from src/main/java/org/gcube/smartgears/configuration/application/Include.java rename to src/main/java/org/gcube/smartgears/configuration/application/GCubeInclude.java index e8486c7..8991456 100644 --- a/src/main/java/org/gcube/smartgears/configuration/application/Include.java +++ b/src/main/java/org/gcube/smartgears/configuration/application/GCubeInclude.java @@ -3,20 +3,14 @@ package org.gcube.smartgears.configuration.application; import java.util.ArrayList; import java.util.List; -import javax.xml.bind.annotation.XmlAccessType; -import javax.xml.bind.annotation.XmlAccessorType; -import javax.xml.bind.annotation.XmlAttribute; -import javax.xml.bind.annotation.XmlRootElement; -import javax.xml.bind.annotation.XmlValue; +import org.gcube.common.validator.annotations.NotEmpty; -@XmlRootElement(name="include") -@XmlAccessorType(XmlAccessType.FIELD) -public class Include { +public class GCubeInclude { - @XmlAttribute(name="handlers") + @NotEmpty private List handlers = new ArrayList(); - @XmlValue + @NotEmpty private String path; public List getHandlers() { @@ -27,14 +21,14 @@ public class Include { return path; } - protected Include() {} + protected GCubeInclude() {} - public Include(String path) { + public GCubeInclude(String path) { super(); this.path = path; } - public Include(List handlers, String path) { + public GCubeInclude(List handlers, String path) { super(); this.handlers = handlers; this.path = path; @@ -57,7 +51,7 @@ public class Include { return false; if (getClass() != obj.getClass()) return false; - Include other = (Include) obj; + GCubeInclude other = (GCubeInclude) obj; if (handlers == null) { if (other.handlers != null) return false; diff --git a/src/main/java/org/gcube/smartgears/configuration/application/ProxyAddress.java b/src/main/java/org/gcube/smartgears/configuration/application/ProxyAddress.java deleted file mode 100644 index ae9bb97..0000000 --- a/src/main/java/org/gcube/smartgears/configuration/application/ProxyAddress.java +++ /dev/null @@ -1,97 +0,0 @@ -package org.gcube.smartgears.configuration.application; - -import javax.xml.bind.annotation.XmlAttribute; -import javax.xml.bind.annotation.XmlElement; -import javax.xml.bind.annotation.XmlRootElement; - -import org.gcube.common.validator.annotations.NotNull; - -@XmlRootElement(name="proxy") -public class ProxyAddress { - - - @XmlAttribute - String protocol = "http"; - - @XmlElement - @NotNull - String hostname; - - @XmlElement - Integer port; - - public String hostname() { - return hostname; - } - - public ProxyAddress hostname(String hostname) { - this.hostname = hostname; - return this; - } - - public Integer port() { - return port; - } - - public ProxyAddress port(int port) { - this.port = port; - return this; - } - - public String protocol() { - return protocol; - } - - public ProxyAddress protocol(String protocol) { - this.protocol = protocol; - return this; - } - - - @Override - public String toString() { - return "ProxyAddress [protocol=" + protocol + ", hostname=" + hostname + ", port=" + port + "]"; - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((hostname == null) ? 0 : hostname.hashCode()); - result = prime * result + ((port == null) ? 0 : port.hashCode()); - result = prime * result + ((protocol == null) ? 0 : protocol.hashCode()); - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - ProxyAddress other = (ProxyAddress) obj; - if (hostname == null) { - if (other.hostname != null) - return false; - } else if (!hostname.equals(other.hostname)) - return false; - if (port == null) { - if (other.port != null) - return false; - } else if (!port.equals(other.port)) - return false; - if (protocol == null) { - if (other.protocol != null) - return false; - } else if (!protocol.equals(other.protocol)) - return false; - return true; - } - - - - - -} diff --git a/src/main/java/org/gcube/smartgears/configuration/container/BaseConfiguration.java b/src/main/java/org/gcube/smartgears/configuration/container/BaseConfiguration.java new file mode 100644 index 0000000..31af311 --- /dev/null +++ b/src/main/java/org/gcube/smartgears/configuration/container/BaseConfiguration.java @@ -0,0 +1,99 @@ +package org.gcube.smartgears.configuration.container; + +import static org.gcube.smartgears.Constants.default_container_publication_frequency_in_seconds; + +import org.gcube.common.validator.annotations.NotEmpty; +import org.gcube.common.validator.annotations.NotNull; +import org.gcube.smartgears.configuration.Mode; + +public class BaseConfiguration { + + + Mode mode = Mode.online; + + @NotNull @NotEmpty + String hostname; + + @NotNull + Integer port; + + @NotNull @NotEmpty + String protocol="http"; + + boolean authorizeChildrenContext = false; + + @NotNull @NotEmpty + String infrastructure; + + long publicationFrequencyInSeconds = default_container_publication_frequency_in_seconds; + + public Mode getMode() { + return mode; + } + + public String getHostname() { + return hostname; + } + + public Integer getPort() { + return port; + } + + public String getProtocol() { + return protocol; + } + + public boolean isAuthorizeChildrenContext() { + return authorizeChildrenContext; + } + + public String getInfrastructure() { + return infrastructure; + } + + + + public long getPublicationFrequencyInSeconds() { + return publicationFrequencyInSeconds; + } + + public void setPublicationFrequencyInSeconds(long publicationFrequencyInSeconds) { + this.publicationFrequencyInSeconds = publicationFrequencyInSeconds; + } + + public void setMode(Mode mode) { + this.mode = mode; + } + + public void setHostname(String hostname) { + this.hostname = hostname; + } + + public void setPort(Integer port) { + this.port = port; + } + + public void setProtocol(String protocol) { + this.protocol = protocol; + } + + public void setAuthorizeChildrenContext(boolean authorizeChildrenContext) { + this.authorizeChildrenContext = authorizeChildrenContext; + } + + public void setInfrastructure(String infrastructure) { + this.infrastructure = infrastructure; + } + + + @Override + public String toString() { + return "BaseConfiguration [mode=" + mode + ", hostname=" + hostname + ", port=" + port + ", protocol=" + + protocol + ", authorizeChildrenContext=" + authorizeChildrenContext + ", infrastructure=" + + infrastructure + ", publicationFrequency=" + publicationFrequencyInSeconds + + "]"; + } + + + +} diff --git a/src/main/java/org/gcube/smartgears/configuration/container/ContainerConfiguration.java b/src/main/java/org/gcube/smartgears/configuration/container/ContainerConfiguration.java index f138d93..128b968 100644 --- a/src/main/java/org/gcube/smartgears/configuration/container/ContainerConfiguration.java +++ b/src/main/java/org/gcube/smartgears/configuration/container/ContainerConfiguration.java @@ -1,20 +1,10 @@ package org.gcube.smartgears.configuration.container; -import static org.gcube.smartgears.Constants.default_container_publication_frequency_in_seconds; -import static org.gcube.smartgears.utils.Utils.notNull; - import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; -import java.util.HashSet; import java.util.List; import java.util.Map; -import java.util.Set; - -import javax.xml.bind.annotation.XmlAttribute; -import javax.xml.bind.annotation.XmlElement; -import javax.xml.bind.annotation.XmlElementRef; -import javax.xml.bind.annotation.XmlRootElement; -import javax.xml.bind.annotation.XmlTransient; import org.gcube.common.validator.ValidationError; import org.gcube.common.validator.Validator; @@ -22,11 +12,11 @@ import org.gcube.common.validator.ValidatorFactory; import org.gcube.common.validator.annotations.IsValid; import org.gcube.common.validator.annotations.NotEmpty; import org.gcube.common.validator.annotations.NotNull; +import org.gcube.smartgears.configuration.AuthorizationProviderConfiguration; import org.gcube.smartgears.configuration.Mode; +import org.gcube.smartgears.configuration.PersistenceConfiguration; +import org.gcube.smartgears.configuration.ProxyAddress; import org.gcube.smartgears.configuration.application.ApplicationConfiguration; -import org.gcube.smartgears.configuration.application.DefaultApplicationConfiguration; -import org.gcube.smartgears.persistence.DefaultPersistence; -import org.gcube.smartgears.persistence.Persistence; /** * The configuration of the container. @@ -34,78 +24,75 @@ import org.gcube.smartgears.persistence.Persistence; * @author Fabio Simeoni * @author Luca Frosini (ISTI - CNR) */ -@XmlRootElement(name="container") public class ContainerConfiguration { - - @XmlAttribute - private Mode mode = Mode.online; - - @XmlElement - @NotNull @IsValid - String hostname; - - @XmlElement - @NotNull - Integer port; - - @XmlElement(name ="authentication-endpoint") - String authenticationEnpoint = null; - - @XmlElement(name ="protocol") - @NotNull @IsValid - String protocol="http"; - - @XmlElement - boolean authorizeChildrenContext = false; - - @XmlElement - @NotNull@IsValid - String infrastructure; + @NotNull @IsValid + private BaseConfiguration baseConfiguration; - @XmlElement - @NotNull @IsValid - Site site; - - @XmlElement(name="token") - @NotNull @NotEmpty - List tokens = new ArrayList(); + @IsValid + private Map properties = new HashMap(); + + @NotNull @IsValid + private Site site; - @XmlTransient - Set allowedContext = new HashSet(); - - @XmlElementRef(type=DefaultApplicationConfiguration.class) - List apps = new ArrayList(); - - @XmlElement(name="property") @IsValid - List properties = new ArrayList(); + private ProxyAddress proxy; + + @NotEmpty @NotNull + private String accountingFallbackLocation; + + private List apps = new ArrayList(); + - @XmlElement(name="publication-frequency") - long publicationFrequency = default_container_publication_frequency_in_seconds; + + @NotNull @IsValid + private PersistenceConfiguration persistenceConfiguration; + + @NotNull @IsValid + private AuthorizationProviderConfiguration authorizationConfiguration; - @XmlElementRef(type=DefaultPersistence.class) - @IsValid - private Persistence persistenceManager; - + + protected void setBaseConfiguration(BaseConfiguration baseConfiguration) { + this.baseConfiguration = baseConfiguration; + } + + protected void setProperties(Map properties) { + this.properties = properties; + } + + protected void setSite(Site site) { + this.site = site; + } + + protected void setProxy(ProxyAddress proxy) { + this.proxy = proxy; + } + + protected void setAccountingFallbackLocation(String accountingFallbackLocation) { + this.accountingFallbackLocation = accountingFallbackLocation; + } + + protected void setPersistenceConfiguration(PersistenceConfiguration persistenceConfiguration) { + this.persistenceConfiguration = persistenceConfiguration; + } + + protected void setAuthorizationProviderConfiguration( + AuthorizationProviderConfiguration authorizationConfiguration) { + this.authorizationConfiguration = authorizationConfiguration; + } + + public void setApps(List apps) { + this.apps = apps; + } + /** * Returns the management mode for the container. * @return the management mode */ public Mode mode() { - return mode; + return baseConfiguration.getMode(); } - - /** - * Sets the management mode for the container. - * @param mode the management mode - * @return this configuration - */ - public ContainerConfiguration mode(Mode mode) { - this.mode=mode; - return this; - } - + /** * Returns the application configurations included in this configuration. * @return the application configurations @@ -113,21 +100,21 @@ public class ContainerConfiguration { public List apps() { return apps; } - + /** * Returns the configuration of an application with a given context path. * @param context the context path * @return the application configuration */ public ApplicationConfiguration app(String context) { - + for (ApplicationConfiguration app : apps) if (context.equals(app.context())) return app; - + return null; } - + /** * Adds the configuration of an application to this configuration. * @param app the application configuration @@ -146,7 +133,7 @@ public class ContainerConfiguration { apps.add(app); return this; } - + /** * Returns the geographical site of the container. * @return the site @@ -155,143 +142,77 @@ public class ContainerConfiguration { return site; } - /** - * Sets the geographical site of the container. - * @param site the site - * @return this configuration - */ - public ContainerConfiguration site(Site site) { - this.site=site; - return this; - } - + /** * Returns the infrastructure in which the container is running. * @return the infrastructure */ public String infrastructure() { - return infrastructure; + return baseConfiguration.getInfrastructure(); } - /** - * Sets the infrastructure in which the container is running. - * @param infrastructure the infrastructure - * @return this configuration - */ - public ContainerConfiguration infrastructure(String infrastructure) { - this.infrastructure=infrastructure; - return this; - } - - - + /** * Returns the host name of the container. * @return the host name; */ public String hostname() { - return hostname; + return baseConfiguration.getHostname(); } - - /** - * Sets the host name of the container. - * @param name the host name - * @return this configuration - */ - public ContainerConfiguration hostname(String name) { - this.hostname=name; - return this; - } - + /** * Returns the port at which the container is listening for requests. * @return the port */ public int port() { - return port; + return baseConfiguration.getPort(); } - - + + /** * Returns the port at which the container is listening for requests. * @return the port */ public String protocol() { - return protocol; - } - - - public String authenticationEnpoint() { - return authenticationEnpoint; - } - - public ContainerConfiguration authenticationEnpoint(String endpoint) { - this.authenticationEnpoint = endpoint; - return this; + return baseConfiguration.getProtocol(); } - /** - * Sets the port at which the container is listening for requests. - * @param port the port - * @return this configuration - */ - public ContainerConfiguration port(int port) { - this.port=port; - return this; - } - - public ContainerConfiguration protocol(String protocol) { - this.protocol=protocol; - return this; - } - + public boolean authorizeChildrenContext() { - return authorizeChildrenContext; - } - - public ContainerConfiguration authorizeChildrenContext(boolean authorizeChildrenContext) { - this.authorizeChildrenContext = authorizeChildrenContext; - return this; + return baseConfiguration.isAuthorizeChildrenContext(); } /** - * Returns the VOs in which the container initially operates. - * @return the VOs + * Returns the proxy of the container. + * @return the proxy */ - public List startTokens() { - return tokens; + public ProxyAddress proxy() { + return proxy; } - - /** - * Sets the VOs in which the container initially operates. - * @param vos the VOs - * @return this configuration - */ - public ContainerConfiguration startTokens(List tokens) { - - notNull("start Tokens",tokens); - - this.tokens = tokens; - - return this; - } - + + /** * Returns the persistence manager of the container. * @return the manager */ - public Persistence persistence() { - return persistenceManager; + public PersistenceConfiguration persistenceConfiguration() { + return this.persistenceConfiguration; } /** - * Sets the persistence manager of the container. - * @param manager the manager - * @return this configuration + * Returns the persistence manager of the container. + * @return the manager */ - public ContainerConfiguration persistence(Persistence manager) { - this.persistenceManager=manager; - return this; + public String accountingFallbackLocation() { + return accountingFallbackLocation; + } + + /** + * Returns the authorization configuration. + * @return AuthorizationProviderConfiguration the configuration + */ + public AuthorizationProviderConfiguration authorizationConfiguration() { + return authorizationConfiguration; } /** @@ -299,48 +220,15 @@ public class ContainerConfiguration { * @return the properties */ public Map properties() { - Map map = new HashMap(); - for (Property prop : properties) - map.put(prop.name, prop.value); - return map; + return Collections.unmodifiableMap(properties); } - /** - * Adds a configuration property to the container. - * @param the name of the property - * @param the value of the property - * @return this configuration - */ - public ContainerConfiguration property(String name, String value) { - properties.add(new Property(name, value)); - return this; - } - /** * Returns the publication frequency for the container's profile. * @return the frquency; */ public long publicationFrequency() { - return publicationFrequency; - } - - /** - * Sets the publication frequency for the container's profile. - * @param frequency the frequency - * @return this configuration - */ - public ContainerConfiguration publicationFrequency(long frequency) { - this.publicationFrequency=frequency; - return this; - } - - - public Set allowedContexts() { - return allowedContext; - } - - public void allowedContexts(Set allowedContexts) { - this.allowedContext = allowedContexts; + return baseConfiguration.getPublicationFrequencyInSeconds(); } /** @@ -353,7 +241,7 @@ public class ContainerConfiguration { List msgs = new ArrayList(); Validator validator = ValidatorFactory.validator(); - + for (ValidationError error : validator.validate(this)) msgs.add(error.toString()); @@ -362,159 +250,14 @@ public class ContainerConfiguration { } - - - static class Property { - - @XmlAttribute @NotNull - String name; - - @XmlAttribute @NotNull - String value; - - Property() {} - - Property(String key, String value) { - this.name=key; - this.value=value; - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((name == null) ? 0 : name.hashCode()); - result = prime * result + ((value == null) ? 0 : value.hashCode()); - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - Property other = (Property) obj; - if (name == null) { - if (other.name != null) - return false; - } else if (!name.equals(other.name)) - return false; - if (value == null) { - if (other.value != null) - return false; - } else if (!value.equals(other.value)) - return false; - return true; - } - - } - - - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((allowedContext == null) ? 0 : allowedContext.hashCode()); - result = prime * result + ((apps == null) ? 0 : apps.hashCode()); - result = prime * result + ((authenticationEnpoint == null) ? 0 : authenticationEnpoint.hashCode()); - result = prime * result + (authorizeChildrenContext ? 1231 : 1237); - result = prime * result + ((hostname == null) ? 0 : hostname.hashCode()); - result = prime * result + ((infrastructure == null) ? 0 : infrastructure.hashCode()); - result = prime * result + ((mode == null) ? 0 : mode.hashCode()); - result = prime * result + ((persistenceManager == null) ? 0 : persistenceManager.hashCode()); - result = prime * result + ((port == null) ? 0 : port.hashCode()); - result = prime * result + ((properties == null) ? 0 : properties.hashCode()); - result = prime * result + ((protocol == null) ? 0 : protocol.hashCode()); - result = prime * result + (int) (publicationFrequency ^ (publicationFrequency >>> 32)); - result = prime * result + ((site == null) ? 0 : site.hashCode()); - result = prime * result + ((tokens == null) ? 0 : tokens.hashCode()); - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - ContainerConfiguration other = (ContainerConfiguration) obj; - if (allowedContext == null) { - if (other.allowedContext != null) - return false; - } else if (!allowedContext.equals(other.allowedContext)) - return false; - if (apps == null) { - if (other.apps != null) - return false; - } else if (!apps.equals(other.apps)) - return false; - if (authenticationEnpoint == null) { - if (other.authenticationEnpoint != null) - return false; - } else if (!authenticationEnpoint.equals(other.authenticationEnpoint)) - return false; - if (authorizeChildrenContext != other.authorizeChildrenContext) - return false; - if (hostname == null) { - if (other.hostname != null) - return false; - } else if (!hostname.equals(other.hostname)) - return false; - if (infrastructure == null) { - if (other.infrastructure != null) - return false; - } else if (!infrastructure.equals(other.infrastructure)) - return false; - if (mode != other.mode) - return false; - if (persistenceManager == null) { - if (other.persistenceManager != null) - return false; - } else if (!persistenceManager.equals(other.persistenceManager)) - return false; - if (port == null) { - if (other.port != null) - return false; - } else if (!port.equals(other.port)) - return false; - if (properties == null) { - if (other.properties != null) - return false; - } else if (!properties.equals(other.properties)) - return false; - if (protocol == null) { - if (other.protocol != null) - return false; - } else if (!protocol.equals(other.protocol)) - return false; - if (publicationFrequency != other.publicationFrequency) - return false; - if (site == null) { - if (other.site != null) - return false; - } else if (!site.equals(other.site)) - return false; - if (tokens == null) { - if (other.tokens != null) - return false; - } else if (!tokens.equals(other.tokens)) - return false; - return true; - } - @Override public String toString() { - return "ContainerConfiguration [mode=" + mode + ", hostname=" + hostname + ", port=" + port + ", authenticationEnpoint=" + authenticationEnpoint + ", protocol=" + protocol - + ", authorizeChildrenContext=" + authorizeChildrenContext + ", infrastructure=" + infrastructure - + ", site=" + site + ", tokens=" + tokens + ", allowedContext=" + allowedContext + ", apps=" + apps - + ", properties=" + properties + ", publicationFrequency=" + publicationFrequency - + ", persistenceManager=" + persistenceManager + "]"; + return "ContainerConfiguration [baseConfiguration=" + baseConfiguration + ", properties=" + properties + + ", site=" + site + ", proxy=" + proxy + ", accountingFallbackLocation=" + accountingFallbackLocation + + ", persistence=" + persistenceConfiguration.getImplementationClass().getSimpleName() + + ", authorizationProvider=" + authorizationConfiguration + "]"; } - + + + } \ No newline at end of file diff --git a/src/main/java/org/gcube/smartgears/configuration/container/ContainerConfigurationBinder.java b/src/main/java/org/gcube/smartgears/configuration/container/ContainerConfigurationBinder.java index 7d112a0..382a803 100644 --- a/src/main/java/org/gcube/smartgears/configuration/container/ContainerConfigurationBinder.java +++ b/src/main/java/org/gcube/smartgears/configuration/container/ContainerConfigurationBinder.java @@ -1,18 +1,31 @@ package org.gcube.smartgears.configuration.container; -import static org.gcube.smartgears.utils.Utils.*; - +import java.io.File; import java.io.InputStream; -import java.lang.reflect.Modifier; -import java.util.HashSet; -import java.util.ServiceLoader; -import java.util.Set; - -import javax.xml.bind.JAXBContext; -import javax.xml.bind.JAXBException; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; +import java.util.Map.Entry; +import java.util.stream.Collectors; +import org.gcube.common.security.credentials.Credentials; +import org.gcube.smartgears.configuration.AuthorizationProviderConfiguration; +import org.gcube.smartgears.configuration.ComponentConfiguration; +import org.gcube.smartgears.configuration.ConfiguredWith; +import org.gcube.smartgears.configuration.PersistenceConfiguration; +import org.gcube.smartgears.configuration.ProxyAddress; +import org.gcube.smartgears.configuration.SmartgearsConfiguration; import org.gcube.smartgears.handlers.container.ContainerHandler; +import org.gcube.smartgears.handlers.container.lifecycle.AccountingManager; +import org.gcube.smartgears.handlers.container.lifecycle.ContainerProfileManager; +import org.gcube.smartgears.persistence.LocalWriter; +import org.gcube.smartgears.persistence.LocalWriterConfiguration; +import org.gcube.smartgears.persistence.PersistenceWriter; +import org.gcube.smartgears.security.AuthorizationProviderFactory; +import org.gcube.smartgears.security.defaults.DefaultAuthorizationProviderFactory; import org.gcube.smartgears.utils.Utils; +import org.ini4j.Ini; +import org.ini4j.Profile.Section; /** * Binds {@link ContainerConfiguration}s to and from XML serialisations. @@ -22,34 +35,138 @@ import org.gcube.smartgears.utils.Utils; */ public class ContainerConfigurationBinder { - /** - * Returns a {@link ContainerConfiguration} from its XML serialisation. - * - * @param stream the serialisation - * @return the configuration - * @throws RuntimeException if the serialisation is invalid - */ - public ContainerConfiguration bind(InputStream stream) { - + public ContainerConfiguration load(InputStream stream) { try { + Ini configurator = new Ini(stream); + ContainerConfiguration conf = new ContainerConfiguration(); - JAXBContext ctx = JAXBContext.newInstance(ContainerConfiguration.class); + Section nodeSection = configurator.get("node"); + if (nodeSection != null) { + BaseConfiguration nodeConf = new BaseConfiguration(); + nodeSection.to(nodeConf); + conf.setBaseConfiguration(nodeConf); + } - ContainerConfiguration config = (ContainerConfiguration) ctx.createUnmarshaller().unmarshal(stream); - - return config; + Section propertiesSection = configurator.get("properties"); + if (propertiesSection != null) + conf.setProperties(propertiesSection.entrySet().stream() + .collect(Collectors.toMap(Entry::getKey, Entry::getValue))); - } catch (JAXBException e) { + Section siteSection = configurator.get("site"); + if (siteSection != null) { + Site siteConf = new Site(); + siteSection.to(siteConf); + conf.setSite(siteConf); + } - throw new RuntimeException("invalid container configuration", e); + initAuthorizationPart(configurator, conf); - } - finally { - - Utils.closeSafely(stream); + initPersistencePart(configurator, conf); + + initProxyPart(configurator, conf); + + // TODO: find a solution for this shit + String location = Utils.home() + "/state"; + File dir = new File(location); + if (!dir.exists()) + dir.mkdirs(); + conf.setAccountingFallbackLocation(location); + // END Shit + + return conf; + } catch (Exception e) { + throw new RuntimeException(e); } } - + + private void initProxyPart(Ini configurator, ContainerConfiguration conf) throws Exception { + Section proxySection = configurator.get("proxy"); + if (proxySection != null) { + ProxyAddress proxyConf = new ProxyAddress(); + proxySection.to(proxyConf); + conf.setProxy(proxyConf); + } + } + + @SuppressWarnings("unchecked") + private void initPersistencePart(Ini configurator, ContainerConfiguration conf) throws Exception { + Section persistenceSection = configurator.get("persistence"); + if (persistenceSection != null) { + String type = persistenceSection.get("class"); + if (type == null) + throw new Exception("ini file error: type not found in \"persistence\" section"); + /* + * PersistenceWriter persistenceWriter; try { Object persistenceImpl = + * Class.forName(type).getDeclaredConstructor().newInstance(); persistenceWriter + * = PersistenceWriter.class.cast(persistenceImpl); }catch (Exception e) { throw + * new + * Exception("ini file error: invalid persistence type in \"persistence\" section" + * , e); } + */ + // persistenceSection.to(persistenceWriter); + + Class persistenceClass = null; + try { + persistenceClass = (Class) Class.forName(type); + } catch (Exception e) { + throw new Exception("ini file error: invalid persistence type in \"persistence\" section", e); + } + if (!persistenceClass.isAnnotationPresent(ConfiguredWith.class)) + throw new Exception( + "ini file error: invalid class type in \"persistence\" section,ConfiguredWith annotation not present"); + Class writerConfClass = persistenceClass + .getAnnotation(ConfiguredWith.class).value(); + ComponentConfiguration writerConfiguration = writerConfClass.getDeclaredConstructor().newInstance(); + persistenceSection.to(writerConfiguration, "."); + conf.setPersistenceConfiguration( + new PersistenceConfiguration((Class) persistenceClass, writerConfiguration)); + } else { + String location = Utils.home() + "/state"; + File dir = new File(location); + if (!dir.exists()) + dir.mkdirs(); + + conf.setPersistenceConfiguration( + new PersistenceConfiguration(LocalWriter.class, new LocalWriterConfiguration(location))); + } + + } + + private void initAuthorizationPart(Ini configurator, ContainerConfiguration conf) throws Exception { + Section authorizationSection = configurator.get("authorization"); + if (authorizationSection != null) { + + String provider = authorizationSection.get("factory"); + AuthorizationProviderFactory authProviderFactory; + if (provider != null) { + try { + Object authProviderImpl = Class.forName(provider).getDeclaredConstructor().newInstance(); + authProviderFactory = AuthorizationProviderFactory.class.cast(authProviderImpl); + } catch (Exception e) { + throw new Exception("ini file error: invalid provider type in \"authorization\" section", e); + } + } else + authProviderFactory = new DefaultAuthorizationProviderFactory(); + + authorizationSection.to(authProviderFactory, "factory."); + + String type = authorizationSection.get("credentials.class"); + if (type == null) + throw new Exception("ini file error: credentials type not found in \"authorization\" section"); + Credentials credentials; + try { + Object credentialsImpl = Class.forName(type).getDeclaredConstructor().newInstance(); + credentials = Credentials.class.cast(credentialsImpl); + } catch (Exception e) { + throw new Exception("ini file error: invalid credentials type in \"authorization\" section", e); + } + authorizationSection.to(credentials, "credentials."); + + conf.setAuthorizationProviderConfiguration( + new AuthorizationProviderConfiguration(authProviderFactory, credentials)); + } + } + /** * Returns the handlers of the container from their XML serialisation. * @@ -57,45 +174,35 @@ public class ContainerConfigurationBinder { * @return the handlers * @throws RuntimeException if the serialisation is invalid */ - public ContainerHandlers bindHandlers(InputStream stream) { + public List bindHandlers(ClassLoader classloader) { - //collects handler classes - Set> classes = scanForConfigurationElements(); + LinkedList handlers = new LinkedList(); + // ADDING BASE Handlers (order is important) + handlers.add(new AccountingManager()); + handlers.add(new ContainerProfileManager()); + + handlers.addAll(scanForContainerHadlers(classloader)); + + return handlers; + + } + + private List scanForContainerHadlers(ClassLoader classloader) throws RuntimeException { + + // TODO: scan for Container Handler + + return Collections.emptyList(); + } + + public SmartgearsConfiguration loadSmartgearsProperty() { try { - - JAXBContext ctx = JAXBContext.newInstance(classes.toArray(new Class[0])); - - return (ContainerHandlers) ctx.createUnmarshaller().unmarshal(stream); - - } catch (JAXBException e) { - - throw unchecked(e); - + Ini configurator = new Ini(this.getClass().getResourceAsStream("smartgears-config.ini")); + String version = configurator.get("smartgears").get("version"); + return new SmartgearsConfiguration(version); + }catch (Exception e) { + throw new RuntimeException(e); } } - - - - private Set> scanForConfigurationElements() throws RuntimeException { - @SuppressWarnings("all") - ServiceLoader handlerLoader = (ServiceLoader) ServiceLoader.load(ContainerHandler.class); - - Set> scanned = new HashSet>(); - - for (ContainerHandler handler : handlerLoader) { - Class handlerClass = handler.getClass(); - if (handlerClass.isInterface() || handlerClass.getModifiers() == Modifier.ABSTRACT) - continue; - else - scanned.add(handlerClass); - } - - //add top-level configuration - scanned.add(ContainerHandlers.class); - - return scanned; - } - } diff --git a/src/main/java/org/gcube/smartgears/configuration/container/ContainerHandlers.java b/src/main/java/org/gcube/smartgears/configuration/container/ContainerHandlers.java deleted file mode 100644 index 73534b8..0000000 --- a/src/main/java/org/gcube/smartgears/configuration/container/ContainerHandlers.java +++ /dev/null @@ -1,50 +0,0 @@ -package org.gcube.smartgears.configuration.container; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -import javax.xml.bind.annotation.XmlAnyElement; -import javax.xml.bind.annotation.XmlRootElement; - -import org.gcube.smartgears.handlers.container.ContainerHandler; - -/** - * The {@link ContainerHandler}s that manage the application. - * - * @author Fabio Simeoni - * - */ -@XmlRootElement(name="handlers") -public class ContainerHandlers { - - @XmlAnyElement(lax=true) - List handlers = new ArrayList(); - - public ContainerHandlers() {} - - /** - * Returns the {@link ContainerHandler}s for the service. - * @return the lifecycle handlers - */ - public List get() { - return handlers; - } - - /** - * Sets the {@link ContainerHandler}s for the service. - * @param handlers the lifecycle handlers - * @return this configuration - */ - public ContainerHandlers set(ContainerHandler ... handlers) { - this.handlers = Arrays.asList(handlers); - return this; - } - - public void mergeWith(ContainerHandlers other){ - List handlers = other.get(); - for (ContainerHandler handler : handlers) - if (!this.get().contains(handler)) - this.get().add(handler); - } -} \ No newline at end of file diff --git a/src/main/java/org/gcube/smartgears/configuration/container/Site.java b/src/main/java/org/gcube/smartgears/configuration/container/Site.java index cc41f4f..e81ce0b 100644 --- a/src/main/java/org/gcube/smartgears/configuration/container/Site.java +++ b/src/main/java/org/gcube/smartgears/configuration/container/Site.java @@ -1,8 +1,5 @@ package org.gcube.smartgears.configuration.container; -import javax.xml.bind.annotation.XmlElement; -import javax.xml.bind.annotation.XmlRootElement; - import org.gcube.common.validator.annotations.NotNull; /** @@ -11,97 +8,28 @@ import org.gcube.common.validator.annotations.NotNull; * @author Fabio Simeoni * */ -@XmlRootElement(name="site") public class Site { - @XmlElement @NotNull String country; - @XmlElement @NotNull String location; - @XmlElement - @NotNull - String latitude; - - @XmlElement - @NotNull - String longitude; - - /** - * Returns the country. - * @return the country - */ - public String country() { + public String getCountry() { return country; } - /** - * Sets the country. - * @param the country - * @return this configuration - */ - public Site country(String country) { - this.country=country; - return this; - } - - - /** - * Returns the latitude. - * @return the latitude - */ - public String latitude() { - return latitude; + public void setCountry(String country) { + this.country = country; } - /** - * Sets the latitude. - * @param the latitude - * @return this configuration - */ - public Site latitude(String latitude) { - this.latitude=latitude; - return this; - } - - - /** - * Returns the longitude. - * @return the longitude - */ - public String longitude() { - return longitude; - } - - /** - * Sets the longitude. - * @param the longitude - * @return this configuration - */ - public Site longitude(String longitude) { - this.longitude=longitude; - return this; - } - - /** - * Returns the location. - * @return the location - */ - public String location() { + public String getLocation() { return location; } - /** - * Sets the location. - * @param the location - * @return this location - */ - public Site location(String location) { - this.location=location; - return this; + public void setLocation(String location) { + this.location = location; } @Override @@ -109,9 +37,7 @@ public class Site { final int prime = 31; int result = 1; result = prime * result + ((country == null) ? 0 : country.hashCode()); - result = prime * result + ((latitude == null) ? 0 : latitude.hashCode()); result = prime * result + ((location == null) ? 0 : location.hashCode()); - result = prime * result + ((longitude == null) ? 0 : longitude.hashCode()); return result; } @@ -129,24 +55,12 @@ public class Site { return false; } else if (!country.equals(other.country)) return false; - if (latitude == null) { - if (other.latitude != null) - return false; - } else if (!latitude.equals(other.latitude)) - return false; if (location == null) { if (other.location != null) return false; } else if (!location.equals(other.location)) return false; - if (longitude == null) { - if (other.longitude != null) - return false; - } else if (!longitude.equals(other.longitude)) - return false; return true; } - - } \ No newline at end of file diff --git a/src/main/java/org/gcube/smartgears/configuration/library/SmartGearsConfiguration.java b/src/main/java/org/gcube/smartgears/configuration/library/SmartGearsConfiguration.java deleted file mode 100644 index 1541837..0000000 --- a/src/main/java/org/gcube/smartgears/configuration/library/SmartGearsConfiguration.java +++ /dev/null @@ -1,79 +0,0 @@ -package org.gcube.smartgears.configuration.library; - -import java.util.ArrayList; -import java.util.List; - -import javax.xml.bind.annotation.XmlAttribute; -import javax.xml.bind.annotation.XmlRootElement; - -import org.gcube.common.validator.ValidationError; -import org.gcube.common.validator.Validator; -import org.gcube.common.validator.ValidatorFactory; -import org.gcube.common.validator.annotations.NotEmpty; - -@XmlRootElement(name="smartgears") -public class SmartGearsConfiguration { - - @XmlAttribute @NotEmpty - private String version; - - public SmartGearsConfiguration(){ - } - - public String version() { - return version; - } - - public SmartGearsConfiguration version(String version) { - this.version=version; - return this; - } - - - /** - * Validates this configuration - * - * @throws IllegalStateException if the configuration is invalid - */ - public void validate() { - - List msgs = new ArrayList(); - - Validator validator = ValidatorFactory.validator(); - - for (ValidationError error : validator.validate(this)) - msgs.add(error.toString()); - - if (!msgs.isEmpty()) - throw new IllegalStateException("invalid configuration: "+msgs); - - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((version == null) ? 0 : version.hashCode()); - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - SmartGearsConfiguration other = (SmartGearsConfiguration) obj; - if (version == null) { - if (other.version != null) - return false; - } else if (!version.equals(other.version)) - return false; - return true; - } - - - -} diff --git a/src/main/java/org/gcube/smartgears/configuration/library/SmartGearsConfigurationBinder.java b/src/main/java/org/gcube/smartgears/configuration/library/SmartGearsConfigurationBinder.java deleted file mode 100644 index 11a9b42..0000000 --- a/src/main/java/org/gcube/smartgears/configuration/library/SmartGearsConfigurationBinder.java +++ /dev/null @@ -1,47 +0,0 @@ -package org.gcube.smartgears.configuration.library; - -import java.io.InputStream; - -import javax.xml.bind.JAXBContext; -import javax.xml.bind.JAXBException; - -import org.gcube.smartgears.configuration.container.ContainerConfiguration; -import org.gcube.smartgears.utils.Utils; - -/** - * Binds {@link ContainerConfiguration}s to and from XML serialisations. - * - * @author Fabio Simeoni - * - */ -public class SmartGearsConfigurationBinder { - - /** - * Returns a {@link ContainerConfiguration} from its XML serialisation. - * - * @param stream the serialisation - * @return the configuration - * @throws RuntimeException if the serialisation is invalid - */ - public SmartGearsConfiguration bind(InputStream stream) { - - try { - - JAXBContext ctx = JAXBContext.newInstance(SmartGearsConfiguration.class); - - SmartGearsConfiguration config = (SmartGearsConfiguration) ctx.createUnmarshaller().unmarshal(stream); - - return config; - - } catch (JAXBException e) { - - throw new RuntimeException("invalid library configuration", e); - - } - finally { - - Utils.closeSafely(stream); - } - } - -} diff --git a/src/main/java/org/gcube/smartgears/context/application/ApplicationContext.java b/src/main/java/org/gcube/smartgears/context/application/ApplicationContext.java index 033cb34..949c420 100644 --- a/src/main/java/org/gcube/smartgears/context/application/ApplicationContext.java +++ b/src/main/java/org/gcube/smartgears/context/application/ApplicationContext.java @@ -7,7 +7,8 @@ import org.gcube.smartgears.configuration.application.ApplicationConfiguration; import org.gcube.smartgears.context.Properties; import org.gcube.smartgears.context.container.ContainerContext; import org.gcube.smartgears.lifecycle.application.ApplicationLifecycle; -import org.gcube.smartgears.persistence.Persistence; +import org.gcube.smartgears.persistence.PersistenceWriter; +import org.gcube.smartgears.security.AuthorizationProvider; /** * The management context of an application. @@ -33,9 +34,6 @@ public interface ApplicationContext { * @return the configuration */ ApplicationConfiguration configuration(); - - - T profile(Class type); /** * Returns the lifecycle of the application. @@ -56,7 +54,7 @@ public interface ApplicationContext { * * @return the manager */ - Persistence persistence(); + PersistenceWriter persistence(); /** * Returns the servlet context of the application. @@ -78,5 +76,11 @@ public interface ApplicationContext { * @return the properties */ Properties properties(); - + + /** + * Returns the authorization provider. + * @return the AuhtorizationProvider + **/ + AuthorizationProvider authorizationProvider(); + } diff --git a/src/main/java/org/gcube/smartgears/context/application/DefaultApplicationContext.java b/src/main/java/org/gcube/smartgears/context/application/DefaultApplicationContext.java index 96f2b3a..5cf5735 100644 --- a/src/main/java/org/gcube/smartgears/context/application/DefaultApplicationContext.java +++ b/src/main/java/org/gcube/smartgears/context/application/DefaultApplicationContext.java @@ -1,16 +1,24 @@ package org.gcube.smartgears.context.application; -import static org.gcube.smartgears.Constants.profile_property; +import static org.gcube.smartgears.Constants.profile_file_path; + +import java.io.File; +import java.io.FileInputStream; +import java.io.ObjectInputStream; +import java.util.UUID; import javax.servlet.ServletContext; import org.gcube.common.events.Hub; -import org.gcube.common.resources.gcore.GCoreEndpoint; +import org.gcube.smartgears.configuration.PersistenceConfiguration; import org.gcube.smartgears.configuration.application.ApplicationConfiguration; import org.gcube.smartgears.context.Properties; import org.gcube.smartgears.context.container.ContainerContext; import org.gcube.smartgears.lifecycle.application.ApplicationLifecycle; -import org.gcube.smartgears.persistence.Persistence; +import org.gcube.smartgears.persistence.PersistenceWriter; +import org.gcube.smartgears.security.AuthorizationProvider; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * Default {@link ApplicationContext} implementation. @@ -20,12 +28,15 @@ import org.gcube.smartgears.persistence.Persistence; */ public class DefaultApplicationContext implements ApplicationContext { + private static Logger log = LoggerFactory.getLogger(DefaultApplicationContext.class); + private final ContainerContext container; private final ServletContext sctx; private final ApplicationConfiguration configuration; private final ApplicationLifecycle lifecycle; private final Properties properties; private final Hub hub; + private final PersistenceWriter persistenceWriter; private final String id; /** @@ -37,14 +48,37 @@ public class DefaultApplicationContext implements ApplicationContext { * @param lifecycle the lifecycle * @param properties the properties */ - public DefaultApplicationContext(String id,ContainerContext container,ServletContext sctx,ApplicationConfiguration configuration, Hub hub, ApplicationLifecycle lifecycle, Properties properties) { + public DefaultApplicationContext(ContainerContext container,ServletContext sctx,ApplicationConfiguration configuration, Hub hub, ApplicationLifecycle lifecycle, Properties properties) { + + PersistenceConfiguration persistenceWriterConf = configuration.persistenceConfiguration(); + + try { + persistenceWriter = persistenceWriterConf.getImplementationClass().getDeclaredConstructor().newInstance(); + persistenceWriter.configure(persistenceWriterConf.getWriterConfiguration()); + }catch (Exception e) { + throw new RuntimeException(e); + } + + File file = persistenceWriter.file(profile_file_path); + String id = null; + if (file.exists()) { + log.info("loading persisted state for application {}", sctx.getContextPath()); + try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file))) { + id = (String) ois.readObject(); + } catch (Exception e) { + log.error("error loading persisted state, creating new uuid", e); + } + } + if (id == null) + id = UUID.randomUUID().toString(); + this.id = id; this.container=container; this.sctx = sctx; this.configuration=configuration; this.hub=hub; this.lifecycle = lifecycle; - this.properties=properties; + this.properties=properties; } /** @@ -52,9 +86,21 @@ public class DefaultApplicationContext implements ApplicationContext { * @param context the other instance */ public DefaultApplicationContext(ApplicationContext context) { - this(context.id(), context.container(),context.application(),context.configuration(),context.events(), context.lifecycle(), new Properties(context.properties())); + this(context.id(), context.persistence(), context.container(),context.application(),context.configuration(),context.events(), context.lifecycle(), new Properties(context.properties())); } + private DefaultApplicationContext(String id, PersistenceWriter writer, ContainerContext container,ServletContext sctx,ApplicationConfiguration configuration, Hub hub, ApplicationLifecycle lifecycle, Properties properties) { + this.id = id; + this.container=container; + this.sctx = sctx; + this.configuration=configuration; + this.hub=hub; + this.lifecycle = lifecycle; + this.properties=properties; + this.persistenceWriter = writer; + + } + @Override public ServletContext application() { return sctx; @@ -65,16 +111,6 @@ public class DefaultApplicationContext implements ApplicationContext { return container; } - @Override - @SuppressWarnings("all") - public T profile(Class type) { - - if (type==GCoreEndpoint.class) - return (T) properties().lookup(profile_property).value(GCoreEndpoint.class); - - throw new IllegalArgumentException("unsupported profile type: "+type); - } - @Override public String name() { //little shortcut for ease of logging return configuration.name(); @@ -96,10 +132,10 @@ public class DefaultApplicationContext implements ApplicationContext { } @Override - public Persistence persistence() { - return configuration.persistence(); + public PersistenceWriter persistence() { + return persistenceWriter; } - + @Override public Properties properties() { return properties; @@ -110,4 +146,12 @@ public class DefaultApplicationContext implements ApplicationContext { return id; } + /** + * Returns the authorization provider. + * @return the AuhtorizationProvider + **/ + public AuthorizationProvider authorizationProvider() { + return container().authorizationProvider(); + } + } diff --git a/src/main/java/org/gcube/smartgears/context/container/ContainerContext.java b/src/main/java/org/gcube/smartgears/context/container/ContainerContext.java index 3c7ae53..e3729a9 100644 --- a/src/main/java/org/gcube/smartgears/context/container/ContainerContext.java +++ b/src/main/java/org/gcube/smartgears/context/container/ContainerContext.java @@ -4,7 +4,8 @@ import org.gcube.common.events.Hub; import org.gcube.smartgears.configuration.container.ContainerConfiguration; import org.gcube.smartgears.context.Properties; import org.gcube.smartgears.lifecycle.container.ContainerLifecycle; -import org.gcube.smartgears.persistence.Persistence; +import org.gcube.smartgears.persistence.PersistenceWriter; +import org.gcube.smartgears.security.AuthorizationProvider; /** * The management context of the container. @@ -21,11 +22,6 @@ public interface ContainerContext { */ ContainerConfiguration configuration(); - /** - * Returns the resource profile of a given type of the container. - * @return the profile - */ - T profile(Class type); /** * Returns the lifecycle of the container @@ -43,7 +39,7 @@ public interface ContainerContext { * Returns the persistence manager of the container. * @return the manager */ - Persistence persistence(); + PersistenceWriter persistenceWriter(); /** * Returns the properties of the container. @@ -52,5 +48,9 @@ public interface ContainerContext { Properties properties(); String id(); + + AuthorizationProvider authorizationProvider(); + + } diff --git a/src/main/java/org/gcube/smartgears/context/container/DefaultContainerContext.java b/src/main/java/org/gcube/smartgears/context/container/DefaultContainerContext.java index 0a599f7..cde9c96 100644 --- a/src/main/java/org/gcube/smartgears/context/container/DefaultContainerContext.java +++ b/src/main/java/org/gcube/smartgears/context/container/DefaultContainerContext.java @@ -1,12 +1,21 @@ package org.gcube.smartgears.context.container; -import static org.gcube.smartgears.Constants.*; +import static org.gcube.smartgears.Constants.container_profile_file_path; + +import java.io.File; +import java.io.FileInputStream; +import java.io.ObjectInputStream; +import java.util.UUID; + import org.gcube.common.events.Hub; -import org.gcube.common.resources.gcore.HostingNode; +import org.gcube.smartgears.configuration.PersistenceConfiguration; import org.gcube.smartgears.configuration.container.ContainerConfiguration; import org.gcube.smartgears.context.Properties; import org.gcube.smartgears.lifecycle.container.ContainerLifecycle; -import org.gcube.smartgears.persistence.Persistence; +import org.gcube.smartgears.persistence.PersistenceWriter; +import org.gcube.smartgears.security.AuthorizationProvider; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * Default {@link ContainerContext} implementation. @@ -16,11 +25,15 @@ import org.gcube.smartgears.persistence.Persistence; */ public class DefaultContainerContext implements ContainerContext { + private static Logger log = LoggerFactory.getLogger(DefaultContainerContext.class); + private final ContainerConfiguration configuration; private final ContainerLifecycle lifecycle; private final Properties properties; private final Hub hub; + private final AuthorizationProvider authorizationProvider; private final String id; + private final PersistenceWriter persistenceWriter; /** * Creates an instance with mandatory parameters. * @param configuration the configuration @@ -28,23 +41,49 @@ public class DefaultContainerContext implements ContainerContext { * @param lifecycle the lifecycle * @param properties the properties */ - public DefaultContainerContext(String id,ContainerConfiguration configuration, Hub hub, ContainerLifecycle lifecycle, + public DefaultContainerContext(ContainerConfiguration configuration, Hub hub, ContainerLifecycle lifecycle, AuthorizationProvider authProvider, Properties properties) { - this.id = id; this.configuration=configuration; this.hub=hub; this.lifecycle = lifecycle; this.properties=properties; + this.authorizationProvider = authProvider; + + PersistenceConfiguration persistenceWriterConf = configuration.persistenceConfiguration(); + + try { + persistenceWriter = persistenceWriterConf.getImplementationClass().getDeclaredConstructor().newInstance(); + persistenceWriter.configure(persistenceWriterConf.getWriterConfiguration()); + }catch (Exception e) { + throw new RuntimeException(e); + } + + File file = persistenceWriter.file(container_profile_file_path); + + String id = null; + if (file.exists()) { + log.info("loading persisted state for container"); + try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file))) { + id = (String) ois.readObject(); + } catch (Exception e) { + log.error("error loading persisted state, creating new uuid", e); + } + + } + if (id == null) { + id = UUID.randomUUID().toString(); + log.info("container id created is {}", id); + + } + + this.id = id; + } - - @SuppressWarnings("all") - public T profile(Class type) { - - if (type==HostingNode.class) - return (T) properties().lookup(container_profile_property).value(HostingNode.class); - - throw new IllegalArgumentException("unsupported profile type: "+type); - }; + + /* + public HostingNode profile() { + return properties().lookup(container_profile_property).value(HostingNode.class); + };*/ @Override public ContainerConfiguration configuration() { @@ -62,8 +101,8 @@ public class DefaultContainerContext implements ContainerContext { } @Override - public Persistence persistence() { - return configuration.persistence(); + public PersistenceWriter persistenceWriter() { + return persistenceWriter; } @Override @@ -76,6 +115,8 @@ public class DefaultContainerContext implements ContainerContext { return id; } - + public AuthorizationProvider authorizationProvider() { + return authorizationProvider; + } } diff --git a/src/main/java/org/gcube/smartgears/extensions/ApiResource.java b/src/main/java/org/gcube/smartgears/extensions/ApiResource.java index 6fab2bd..1be961e 100644 --- a/src/main/java/org/gcube/smartgears/extensions/ApiResource.java +++ b/src/main/java/org/gcube/smartgears/extensions/ApiResource.java @@ -9,7 +9,7 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.gcube.smartgears.Constants; -import org.gcube.smartgears.configuration.application.Exclude; +import org.gcube.smartgears.configuration.application.GCubeExclude; /** * A resource-specifc API handled by an {@link HttpController}. @@ -53,10 +53,10 @@ public abstract class ApiResource extends HttpExtension { } @Override - public Set excludes() { - return Collections.singleton(new Exclude(Constants.root_mapping+mapping())); + public Set excludes() { + return Collections.singleton(new GCubeExclude(Constants.root_mapping+mapping())); } - + /** * Returns true if this resource supports a given method. * @param method the method diff --git a/src/main/java/org/gcube/smartgears/extensions/ApplicationExtension.java b/src/main/java/org/gcube/smartgears/extensions/ApplicationExtension.java index c4216d6..0d130d1 100644 --- a/src/main/java/org/gcube/smartgears/extensions/ApplicationExtension.java +++ b/src/main/java/org/gcube/smartgears/extensions/ApplicationExtension.java @@ -4,7 +4,7 @@ import java.util.Set; import javax.servlet.Servlet; -import org.gcube.smartgears.configuration.application.Exclude; +import org.gcube.smartgears.configuration.application.GCubeExclude; import org.gcube.smartgears.context.application.ApplicationContext; /** @@ -22,6 +22,8 @@ public interface ApplicationExtension extends Servlet { */ void init(ApplicationContext context) throws Exception; + void stop(); + /** * Returns the name of this extension. * @return the name @@ -39,5 +41,5 @@ public interface ApplicationExtension extends Servlet { * Returns the set of request paths that should be excluded from request management. * @return the set of request paths that should be excluded from request management */ - Set excludes(); + Set excludes(); } diff --git a/src/main/java/org/gcube/smartgears/extensions/HttpController.java b/src/main/java/org/gcube/smartgears/extensions/HttpController.java index 8a2d7a7..cab2e79 100644 --- a/src/main/java/org/gcube/smartgears/extensions/HttpController.java +++ b/src/main/java/org/gcube/smartgears/extensions/HttpController.java @@ -1,8 +1,13 @@ package org.gcube.smartgears.extensions; -import static org.gcube.smartgears.Constants.*; -import static org.gcube.smartgears.handlers.application.request.RequestError.*; -import static org.gcube.smartgears.utils.Utils.*; +import static org.gcube.smartgears.Constants.accept; +import static org.gcube.smartgears.Constants.allow; +import static org.gcube.smartgears.Constants.content_type; +import static org.gcube.smartgears.handlers.application.request.RequestError.incoming_contenttype_unsupported_error; +import static org.gcube.smartgears.handlers.application.request.RequestError.method_unsupported_error; +import static org.gcube.smartgears.handlers.application.request.RequestError.outgoing_contenttype_unsupported_error; +import static org.gcube.smartgears.handlers.application.request.RequestError.resource_notfound_error; +import static org.gcube.smartgears.utils.Utils.notNull; import java.io.IOException; import java.util.Collection; @@ -17,7 +22,7 @@ import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import org.gcube.smartgears.configuration.application.Exclude; +import org.gcube.smartgears.configuration.application.GCubeExclude; import org.gcube.smartgears.context.application.ApplicationContext; /** @@ -69,9 +74,17 @@ public class HttpController extends HttpExtension { } @Override - public Set excludes() { + public void stop(){ + for (ApiResource resource : resources.values()) + resource.stop(); - Set resourceExcludes = new LinkedHashSet(); + } + + + @Override + public Set excludes() { + + Set resourceExcludes = new LinkedHashSet(); for (ApiResource resource : resources.values()) resourceExcludes.addAll(resource.excludes()); @@ -176,8 +189,6 @@ public class HttpController extends HttpExtension { case OPTIONS: resource.doOptions(request, response); break; - case TRACE: - resource.doTrace(request, response); } } diff --git a/src/main/java/org/gcube/smartgears/extensions/HttpExtension.java b/src/main/java/org/gcube/smartgears/extensions/HttpExtension.java index c97a9e7..ef0e3e8 100644 --- a/src/main/java/org/gcube/smartgears/extensions/HttpExtension.java +++ b/src/main/java/org/gcube/smartgears/extensions/HttpExtension.java @@ -1,17 +1,15 @@ package org.gcube.smartgears.extensions; -import static org.gcube.common.events.impl.Utils.*; +import static org.gcube.common.events.impl.Utils.valid; import java.util.HashSet; import java.util.Set; import javax.servlet.http.HttpServlet; -import javax.xml.bind.annotation.XmlAttribute; import org.gcube.common.validator.annotations.NotEmpty; -import org.gcube.smartgears.configuration.application.Exclude; +import org.gcube.smartgears.configuration.application.GCubeExclude; import org.gcube.smartgears.context.application.ApplicationContext; - /** * An {@link ApplicationExtension} that implements the {@link HttpServlet} interface * @@ -27,13 +25,31 @@ public abstract class HttpExtension extends HttpServlet implements ApplicationEx * */ public static enum Method { - GET, PUT, POST, HEAD, DELETE, OPTIONS, TRACE + GET("GET"), + PUT("PUT"), + POST("POST"), + HEAD("HEAD"), + DELETE("DELETE"), + OPTIONS("OPTIONS"); + + + private String value; + + + private Method(String value) { + this.value = value; + } + + + public String getValue() { + return this.value; + } } - @XmlAttribute @NotEmpty + @NotEmpty private String name; - @XmlAttribute @NotEmpty + @NotEmpty private String mapping; private ApplicationContext context; @@ -59,8 +75,11 @@ public abstract class HttpExtension extends HttpServlet implements ApplicationEx } @Override - public Set excludes() { - return new HashSet(); //all managed by default + public void stop() {} + + @Override + public Set excludes() { + return new HashSet(); //all managed by default } protected ApplicationContext context() { diff --git a/src/main/java/org/gcube/smartgears/extensions/resource/ConfigurationResource.java b/src/main/java/org/gcube/smartgears/extensions/resource/ConfigurationResource.java index 0e3c939..ded8c0d 100644 --- a/src/main/java/org/gcube/smartgears/extensions/resource/ConfigurationResource.java +++ b/src/main/java/org/gcube/smartgears/extensions/resource/ConfigurationResource.java @@ -1,6 +1,6 @@ package org.gcube.smartgears.extensions.resource; -import static org.gcube.smartgears.Constants.application_xml; +import static org.gcube.smartgears.Constants.application_json; import static org.gcube.smartgears.extensions.HttpExtension.Method.GET; import java.io.IOException; @@ -9,9 +9,8 @@ import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import org.gcube.common.resources.gcore.Resources; +import org.gcube.com.fasterxml.jackson.databind.ObjectMapper; import org.gcube.smartgears.configuration.application.ApplicationConfiguration; -import org.gcube.smartgears.configuration.application.BridgedApplicationConfiguration; import org.gcube.smartgears.extensions.ApiResource; import org.gcube.smartgears.extensions.ApiSignature; @@ -27,7 +26,7 @@ public class ConfigurationResource extends ApiResource { public static final String mapping = "/configuration"; - private static final ApiSignature signature = handles(mapping).with(method(GET).produces(application_xml)); + private static final ApiSignature signature = handles(mapping).with(method(GET).produces(application_json)); ConfigurationResource() { super(signature); @@ -37,8 +36,8 @@ public class ConfigurationResource extends ApiResource { @Override public void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { - ApplicationConfiguration config = BridgedApplicationConfiguration.class.cast(context().configuration()).inner(); - Resources.marshal(config,resp.getWriter()); + ApplicationConfiguration config = context().configuration(); + new ObjectMapper().writeValue(resp.getWriter(), config); } } diff --git a/src/main/java/org/gcube/smartgears/extensions/resource/FrontPageResource.java b/src/main/java/org/gcube/smartgears/extensions/resource/FrontPageResource.java index a587d0c..c008853 100644 --- a/src/main/java/org/gcube/smartgears/extensions/resource/FrontPageResource.java +++ b/src/main/java/org/gcube/smartgears/extensions/resource/FrontPageResource.java @@ -4,18 +4,14 @@ import static org.gcube.smartgears.Constants.application_xhtml; import static org.gcube.smartgears.Constants.frontpage_file_path; import static org.gcube.smartgears.extensions.HttpExtension.Method.GET; import static org.gcube.smartgears.handlers.application.request.RequestError.application_error; -import static org.gcube.smartgears.provider.ProviderFactory.provider; import static org.gcube.smartgears.utils.Utils.closeSafely; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; -import java.util.Collection; import java.util.HashMap; -import java.util.HashSet; import java.util.Map; -import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -23,10 +19,9 @@ import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import org.gcube.common.resources.gcore.GCoreEndpoint; -import org.gcube.common.scope.impl.ScopeBean; import org.gcube.smartgears.extensions.ApiResource; import org.gcube.smartgears.extensions.ApiSignature; +import org.gcube.smartgears.provider.ProviderFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -93,42 +88,12 @@ public class FrontPageResource extends ApiResource { values.put("version", context().configuration().version()); String infrastructure = context().container().configuration().infrastructure(); - StringBuilder voValue = new StringBuilder(); - - Collection scopes = context().profile(GCoreEndpoint.class).scopes().asCollection(); - Set vos = new HashSet(); - - //pre-process - for (String scope : scopes) { - ScopeBean bean = new ScopeBean(scope); - switch (bean.type()) { - case INFRASTRUCTURE: - infrastructure = bean.name(); - break; - case VO: - vos.add(bean.name()); - break; - case VRE: - vos.add(bean.enclosingScope().name()); - infrastructure=bean.enclosingScope().enclosingScope().name(); - } - } - - //build vo value - int i = 0; - int max = vos.size()-1; - for (String vo : vos) { - String voPrefix = i == 0 ? "" : (i==max?" and ":", "); - voValue.append(voPrefix+"" + vo + ""); - i++; - } - + values.put("infra", infrastructure); - values.put("vos", voValue.toString()); values.put("status", context().lifecycle().state().toString()); - values.put("smartgears-version", provider().smartgearsConfiguration().version()); + values.put("smartgears-version", ProviderFactory.provider().smartgearsConfiguration().getVersion()); return values; } diff --git a/src/main/java/org/gcube/smartgears/extensions/resource/HealthResource.java b/src/main/java/org/gcube/smartgears/extensions/resource/HealthResource.java new file mode 100644 index 0000000..a084d12 --- /dev/null +++ b/src/main/java/org/gcube/smartgears/extensions/resource/HealthResource.java @@ -0,0 +1,105 @@ +package org.gcube.smartgears.extensions.resource; + +import static org.gcube.smartgears.Constants.application_json; +import static org.gcube.smartgears.extensions.HttpExtension.Method.GET; + +import java.io.IOException; +import java.io.PrintWriter; +import java.util.Set; +import java.util.Timer; +import java.util.stream.Collectors; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.gcube.com.fasterxml.jackson.databind.ObjectMapper; +import org.gcube.common.health.api.HealthCheck; +import org.gcube.common.health.api.ReadinessChecker; +import org.gcube.smartgears.context.application.ApplicationContext; +import org.gcube.smartgears.extensions.ApiResource; +import org.gcube.smartgears.extensions.ApiSignature; +import org.gcube.smartgears.health.HealthManager; +import org.gcube.smartgears.health.HealthResponse; +import org.gcube.smartgears.health.HealthTask; +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; + +public class HealthResource extends ApiResource { + + private static final long serialVersionUID = 1L; + + private static Logger log = LoggerFactory.getLogger(HealthResource.class); + + public static final String mapping = "/health"; + + private static final ApiSignature signature = handles(mapping).with(method(GET).produces(application_json)); + + private HealthManager manager; + + private HealthTask task; + + private Timer timer; + + HealthResource() { + super(signature); + } + + @Override + public void init(ApplicationContext context) throws Exception { + Set> annotatedReadiness; + + try (ScanResult result = new ClassGraph().enableClassInfo().enableAnnotationInfo().scan()) { + + ClassInfoList classInfos = result.getClassesWithAnnotation(ReadinessChecker.class.getName()); + + annotatedReadiness = classInfos.stream().map(ClassInfo::loadClass) + .filter(c -> HealthCheck.class.isAssignableFrom(c)).collect(Collectors.toSet()); + } + + manager = new HealthManager(); + for (Class readnessClass : annotatedReadiness) + try { + manager.register((HealthCheck) readnessClass.getDeclaredConstructor().newInstance()); + log.info("added class {} to health manager", readnessClass.getCanonicalName()); + } catch (Throwable e) { + log.error("healthChecker class {} cannot be instantiated", readnessClass.getCanonicalName(), e); + } + + task = new HealthTask(manager); + + timer = new Timer(true); + + timer.scheduleAtFixedRate(task, 10000, 60000); + + super.init(context); + } + + public void stop() { + if (timer!=null) + timer.cancel(); + } + + @Override + public void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + PrintWriter out = resp.getWriter(); + resp.setContentType("application/json"); + resp.setCharacterEncoding("UTF-8"); + HealthResponse response = readiness(); + + new ObjectMapper().writeValue(out, response); + + out.flush(); + } + + public HealthResponse readiness() { + return task.getResponse(); + } + + +} \ No newline at end of file diff --git a/src/main/java/org/gcube/smartgears/extensions/resource/LifecycleResource.java b/src/main/java/org/gcube/smartgears/extensions/resource/LifecycleResource.java index 072ca7f..7532484 100644 --- a/src/main/java/org/gcube/smartgears/extensions/resource/LifecycleResource.java +++ b/src/main/java/org/gcube/smartgears/extensions/resource/LifecycleResource.java @@ -11,8 +11,6 @@ import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import javax.xml.bind.annotation.XmlRootElement; -import javax.xml.bind.annotation.XmlValue; import org.gcube.common.resources.gcore.Resources; import org.gcube.smartgears.extensions.ApiResource; @@ -86,10 +84,8 @@ public class LifecycleResource extends ApiResource { // helper classes - @XmlRootElement(name="state") public static class State { - @XmlValue public String value; State() { diff --git a/src/main/java/org/gcube/smartgears/extensions/resource/MetricsResource.java b/src/main/java/org/gcube/smartgears/extensions/resource/MetricsResource.java new file mode 100644 index 0000000..51cb27d --- /dev/null +++ b/src/main/java/org/gcube/smartgears/extensions/resource/MetricsResource.java @@ -0,0 +1,38 @@ +package org.gcube.smartgears.extensions.resource; + +import static org.gcube.smartgears.Constants.plain_text; +import static org.gcube.smartgears.extensions.HttpExtension.Method.GET; + +import java.io.IOException; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.gcube.smartgears.extensions.ApiResource; +import org.gcube.smartgears.extensions.ApiSignature; + +import io.micrometer.core.instrument.Metrics; +import io.micrometer.prometheus.PrometheusMeterRegistry; + +public class MetricsResource extends ApiResource { + + private static final long serialVersionUID = 1L; + + public static final String mapping = "/metrics"; + + private static final ApiSignature signature = handles(mapping).with(method(GET).produces(plain_text)); + + + MetricsResource() { + super(signature); + } + + + @Override + public void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + PrometheusMeterRegistry registry = (PrometheusMeterRegistry) Metrics.globalRegistry.getRegistries().stream().findFirst().get(); + registry.scrape(resp.getWriter()); + } + +} \ No newline at end of file diff --git a/src/main/java/org/gcube/smartgears/extensions/resource/ProfileResource.java b/src/main/java/org/gcube/smartgears/extensions/resource/ProfileResource.java index 9e76f66..0ac19c8 100644 --- a/src/main/java/org/gcube/smartgears/extensions/resource/ProfileResource.java +++ b/src/main/java/org/gcube/smartgears/extensions/resource/ProfileResource.java @@ -9,8 +9,6 @@ import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import org.gcube.common.resources.gcore.GCoreEndpoint; -import org.gcube.common.resources.gcore.Resources; import org.gcube.smartgears.extensions.ApiResource; import org.gcube.smartgears.extensions.ApiSignature; @@ -36,7 +34,8 @@ public class ProfileResource extends ApiResource { @Override public void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { - Resources.marshal(context().profile(GCoreEndpoint.class),resp.getWriter()); + //Resources.marshal(context().profile(),resp.getWriter()); + //TODO: return something to show } } diff --git a/src/main/java/org/gcube/smartgears/extensions/resource/RemoteResource.java b/src/main/java/org/gcube/smartgears/extensions/resource/RemoteResource.java index 1acbf96..e3fe3f2 100644 --- a/src/main/java/org/gcube/smartgears/extensions/resource/RemoteResource.java +++ b/src/main/java/org/gcube/smartgears/extensions/resource/RemoteResource.java @@ -1,8 +1,6 @@ package org.gcube.smartgears.extensions.resource; -import static org.gcube.smartgears.Constants.*; - -import javax.xml.bind.annotation.XmlRootElement; +import static org.gcube.smartgears.Constants.remote_management; import org.gcube.smartgears.Constants; import org.gcube.smartgears.extensions.ApiResource; @@ -14,7 +12,6 @@ import org.gcube.smartgears.extensions.HttpController; * @author Fabio Simeoni * */ -@XmlRootElement(name = remote_management) public class RemoteResource extends HttpController { private static final String default_mapping = Constants.root_mapping+"/*"; @@ -27,7 +24,7 @@ public class RemoteResource extends HttpController { public RemoteResource() { super(remote_management, default_mapping); addResources(new FrontPageResource(), new ConfigurationResource(), new ProfileResource(), - new LifecycleResource()); + new LifecycleResource(), new MetricsResource(), new HealthResource()); } @Override diff --git a/src/main/java/org/gcube/smartgears/handlers/ProfilePublisher.java b/src/main/java/org/gcube/smartgears/handlers/ProfilePublisher.java index 6c3e374..c928c50 100644 --- a/src/main/java/org/gcube/smartgears/handlers/ProfilePublisher.java +++ b/src/main/java/org/gcube/smartgears/handlers/ProfilePublisher.java @@ -3,21 +3,14 @@ package org.gcube.smartgears.handlers; import java.util.Collection; public interface ProfilePublisher { - - /** - * Adds for the first time the current resource profile of the application in one or more scopes. - * @param scopes the scopes - */ - void addTo(Collection tokens); + + void addTo(Collection contexts); void addToAll(); - + void update(); - /** - * Removes the application from one or more scopes. - * @param scopes the scopes - */ - void removeFrom(Collection tokens); + void removeFrom(Collection contexts); -} \ No newline at end of file + +} diff --git a/src/main/java/org/gcube/smartgears/handlers/application/RequestHandler.java b/src/main/java/org/gcube/smartgears/handlers/application/RequestHandler.java index 07f83e2..95fa9d2 100644 --- a/src/main/java/org/gcube/smartgears/handlers/application/RequestHandler.java +++ b/src/main/java/org/gcube/smartgears/handlers/application/RequestHandler.java @@ -22,6 +22,10 @@ public abstract class RequestHandler extends AbstractHandler implements Applicat abstract public String getName(); + public boolean isUnfiltrable() { + return false; + } + /** * Initialises the handler. * diff --git a/src/main/java/org/gcube/smartgears/handlers/application/lifecycle/ProfileManager.java b/src/main/java/org/gcube/smartgears/handlers/application/lifecycle/ApplicationProfileManager.java similarity index 55% rename from src/main/java/org/gcube/smartgears/handlers/application/lifecycle/ProfileManager.java rename to src/main/java/org/gcube/smartgears/handlers/application/lifecycle/ApplicationProfileManager.java index 5859cb8..8c9eafe 100644 --- a/src/main/java/org/gcube/smartgears/handlers/application/lifecycle/ProfileManager.java +++ b/src/main/java/org/gcube/smartgears/handlers/application/lifecycle/ApplicationProfileManager.java @@ -2,36 +2,31 @@ package org.gcube.smartgears.handlers.application.lifecycle; import static org.gcube.common.events.Observes.Kind.resilient; import static org.gcube.smartgears.Constants.profile_management; -import static org.gcube.smartgears.Constants.profile_property; import static org.gcube.smartgears.handlers.ProfileEvents.addToContext; import static org.gcube.smartgears.handlers.ProfileEvents.changed; -import static org.gcube.smartgears.handlers.ProfileEvents.published; 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.lifecycle.application.ApplicationState.failed; import java.util.Collections; +import java.util.List; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; -import javax.xml.bind.annotation.XmlRootElement; - import org.gcube.common.events.Observes; import org.gcube.common.events.Observes.Kind; -import org.gcube.common.resources.gcore.GCoreEndpoint; import org.gcube.smartgears.Constants; import org.gcube.smartgears.configuration.Mode; import org.gcube.smartgears.context.Property; import org.gcube.smartgears.context.application.ApplicationContext; -import org.gcube.smartgears.handlers.OfflineProfilePublisher; -import org.gcube.smartgears.handlers.ProfilePublisher; import org.gcube.smartgears.handlers.application.ApplicationLifecycleEvent; 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.provider.ProviderFactory; +import org.gcube.smartgears.publishing.Publisher; import org.gcube.smartgears.utils.Utils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -52,29 +47,24 @@ import org.slf4j.LoggerFactory; * * * @author Fabio Simeoni - * @see ProfileBuilder - * @see ProfilePublisherImpl */ -@XmlRootElement(name = profile_management) -public class ProfileManager extends ApplicationLifecycleHandler { +public class ApplicationProfileManager extends ApplicationLifecycleHandler { - Logger log = LoggerFactory.getLogger(ProfileManager.class); + Logger log = LoggerFactory.getLogger(ApplicationProfileManager.class); private ApplicationContext context; - private ProfileBuilder builder; - private ProfilePublisher publisher; - private ScheduledFuture periodicUpdates; + private static final String PUBLISHED_PROP = "published"; + private List publishers = ProviderFactory.provider().publishers(); + @Override public void onStart(ApplicationLifecycleEvent.Start e) { context = e.context(); - builder = new ProfileBuilder(context); activated(); - - schedulePeriodicUpdates(); + // note we don't fire profile events, but wait for the final startup // outcome which // will result in a state change. only then we publish and store the @@ -89,16 +79,13 @@ public class ProfileManager extends ApplicationLifecycleHandler { private void activated(){ - GCoreEndpoint profile = loadOrCreateProfile(); - share(profile); - - publisher = context.container().configuration().mode()!=Mode.offline? - new ProfilePublisherImpl(context): - new OfflineProfilePublisher(); - + publishers = context.container().configuration().mode()!=Mode.offline? + ProviderFactory.provider().publishers(): + Collections.emptyList(); registerObservers(); + schedulePeriodicUpdates(); } // helpers @@ -109,141 +96,100 @@ public class ProfileManager extends ApplicationLifecycleHandler { @Observes({ activation, stop, failure }) void onChanged(ApplicationLifecycle lc) { - GCoreEndpoint profile = context.profile(GCoreEndpoint.class); - - profile.profile().deploymentData().status(lc.state().remoteForm()); - log.debug("moving app {} to {}",context.name(), lc.state().remoteForm()); // since we do not know the observers, they will deal with // failures and their consequences // any that comes back will be logged in this event thread - context.events().fire(profile, changed); + context.events().fire(context, changed); } + /* @Observes(value = published) void shareAfterPublish(GCoreEndpoint profile) { share(profile); // publish may produce a new profile instance - } + }*/ @Observes(value = changed, kind = Kind.safe) - void publishAfterChange(GCoreEndpoint profile) { + void publishAfterChange(ApplicationContext context) { - boolean firstPublication = profile.scopes().isEmpty(); //if we've failed before first publication do not try to publish //(we may well have failed there) - try { - - if (firstPublication) { - if (context.lifecycle().state()!= failed) - publishFirstTime(profile); - } - else{ - log.debug("update app {} profile",context.name()); - publisher.update(); // if successful, triggers share. + if (!context.properties().contains(PUBLISHED_PROP)) { + log.info("publishing application for the first time"); + context.properties().add(new Property(PUBLISHED_PROP, true)); + if (context.lifecycle().state() != ApplicationState.failed) { + publishers.forEach(p -> { + try { + p.create(context, + context.container().authorizationProvider().getContexts()); + }catch (Exception e) { + log.error("cannot publish {} for first time with publisher type {} (see details)",context.name(), p.getClass().getCanonicalName(), e); + } + }); } } - catch (Exception e) { - - log.error("cannot publish "+context.name()+" (see details)", e); - - // since we've failed no published event is fired and profile - // will not be stored. - // we do it manually to ensure we leave some local trace of the - // changed profile. - //TODO: CHECK --- store(profile); - } - - - - } - - @Observes(value = addToContext) - void addTo(String token) { - try { - log.trace("publishing application with new token"); - publisher.addTo(Collections.singleton(token)); - publisher.update(); - }catch (Exception e) { - - log.error("cannot add token {} (see details)",token, e); - - // since we've failed no published event is fired and profile - // will not be stored. - // we do it manually to ensure we leave some local trace of the - // changed profile. - //TODO: CHECK --- store(profile); - } - - } - - @Observes(value = removeFromContext) - void removeFrom(String token) { - try { - log.trace("unpublishing application with token"); - publisher.removeFrom(Collections.singleton(token)); - publisher.update(); - }catch (Exception e) { - - log.error("cannot remove token {} (see details)",token, e); - - // since we've failed no published event is fired and profile - // will not be stored. - // we do it manually to ensure we leave some local trace of the - // changed profile. - //TODO: CHECK --- store(profile); - } + else + publishers.forEach(p -> { + try { + p.update(context); + }catch (Exception e) { + log.error("cannot publish {} with publisher type {} (see details)",context.name(), p.getClass().getCanonicalName(), e); + } + }); } }); - } + //registering ContextObserver in container HUB + context.container().events().subscribe(new Object() { - private void share(GCoreEndpoint profile) { + @Observes(value = addToContext) + void addTo(String scope) { + log.info("add_to_context event arrived in app {}", context.name()); + for (Publisher publisher: publishers) + try { + log.debug("publishing application in context {}", scope); + publisher.create(context, + Collections.singleton(scope)); - log.trace("sharing profile for {}", context.name()); + }catch (Exception e) { - context.properties().add(new Property(profile_property, profile)); - } + log.error("cannot add context {} with publisher type {} (see details)",scope, publisher.getClass().getCanonicalName(), e); - private void publishFirstTime(GCoreEndpoint profile) { + // since we've failed no published event is fired and profile + // will not be stored. + // we do it manually to ensure we leave some local trace of the + // changed profile. + //TODO: CHECK --- store(profile); + } - try { + } - publisher.addToAll(); + @Observes(value = removeFromContext) + void removeFrom(String scope) { + log.info("remove_from_context event arrived in app {}", context.name()); + for (Publisher publisher: publishers) + try { + log.debug("unpublishing application from scope {}", scope); + publisher.remove(context, + Collections.singleton(scope)); + }catch (Exception e) { - } catch (Exception e) { - log.warn("publishing failed",e); - } - } + log.error("cannot remove scope {} with publisher type {} (see details)",scope, publisher.getClass().getCanonicalName(), e); - private GCoreEndpoint loadOrCreateProfile() { + // since we've failed no published event is fired and profile + // will not be stored. + // we do it manually to ensure we leave some local trace of the + // changed profile. + //TODO: CHECK --- store(profile); + } - return create(); - } - - private GCoreEndpoint create() { - - log.info("creating profile for {}", context.name()); - - try { - - GCoreEndpoint profile = new GCoreEndpoint(); - profile.setId(context.id()); - - builder.fill(profile); - - return profile; - - } catch (RuntimeException e) { - - // this is a critical startup failure: it will fail the application - throw new RuntimeException("cannot create profile for " + context.name(), e); - - } + } + }); } @@ -270,16 +216,16 @@ public class ProfileManager extends ApplicationLifecycleHandler { final Runnable updateTask = new Runnable() { public void run() { - GCoreEndpoint profile = context.profile(GCoreEndpoint.class); - //if handling of event generates failures these will be reported //for resilience we do not fail the application - log.trace("firing change event on application {} profile", context.name()); - context.events().fire(profile,changed); + log.trace("firing change event on application {} ", context.name()); + context.events().fire(context,changed); } }; - periodicUpdates = Utils.scheduledServicePool.scheduleAtFixedRate(updateTask, Constants.application_republish_frequency_in_minutes, Constants.application_republish_frequency_in_minutes , TimeUnit.MINUTES); + periodicUpdates = Utils.scheduledServicePool.scheduleAtFixedRate(updateTask, + Constants.application_republish_frequency_in_minutes, + Constants.application_republish_frequency_in_minutes , TimeUnit.MINUTES); } @@ -294,7 +240,7 @@ public class ProfileManager extends ApplicationLifecycleHandler { periodicUpdates=null; } catch(Exception e) { - log.warn("could not stop periodic updates of application {} profile", context.name(),e); + log.warn("could not stop periodic updates of application {}", context.name(),e); } } } @@ -302,8 +248,8 @@ public class ProfileManager extends ApplicationLifecycleHandler { }); } - - + + @Override public String toString() { return profile_management; diff --git a/src/main/java/org/gcube/smartgears/handlers/application/lifecycle/ProfileBuilder.java b/src/main/java/org/gcube/smartgears/handlers/application/lifecycle/ProfileBuilder.java deleted file mode 100644 index da9c635..0000000 --- a/src/main/java/org/gcube/smartgears/handlers/application/lifecycle/ProfileBuilder.java +++ /dev/null @@ -1,72 +0,0 @@ -package org.gcube.smartgears.handlers.application.lifecycle; - -import java.net.URI; -import java.util.Arrays; -import java.util.Calendar; -import java.util.List; - -import javax.servlet.ServletRegistration; - -import org.gcube.common.resources.gcore.GCoreEndpoint; -import org.gcube.common.resources.gcore.HostingNode; -import org.gcube.smartgears.configuration.application.ApplicationConfiguration; -import org.gcube.smartgears.configuration.container.ContainerConfiguration; -import org.gcube.smartgears.context.application.ApplicationContext; - -public class ProfileBuilder { - - private static List servletExcludes = Arrays.asList("default","jsp"); - - // private static final Logger log = LoggerFactory.getLogger(ProfileBuilder.class); - - private ApplicationContext context; - - public ProfileBuilder(ApplicationContext context) { - this.context = context; - } - - public void fill(GCoreEndpoint endpoint) { - - - ApplicationConfiguration configuration = context.configuration(); - ContainerConfiguration container = context.container().configuration(); - - - endpoint.profile() - .description(configuration.description()) - .serviceName(configuration.name()) - .serviceClass(configuration.serviceClass()) - .version(configuration.version()) - .serviceId(configuration.name() + configuration.serviceClass() + configuration.version()) - .ghnId(context.container().profile(HostingNode.class).id()); - - endpoint.profile().newDeploymentData() - .activationTime(Calendar.getInstance()) - .status((context.lifecycle().state().remoteForm())); - - endpoint.profile().endpoints().clear(); - - 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,context.application().getContextPath()); - } else { - String protocol = container.protocol(); - int port = container.port(); - - baseAddress=String.format("%s://%s:%d%s", protocol , container.hostname(), port,context.application().getContextPath()); - } - - for (ServletRegistration servlet : context.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); - endpoint.profile().endpoints().add().nameAndAddress(servlet.getName(),URI.create(address)); - } - - - } - -} diff --git a/src/main/java/org/gcube/smartgears/handlers/application/lifecycle/ProfilePublisherImpl.java b/src/main/java/org/gcube/smartgears/handlers/application/lifecycle/ProfilePublisherImpl.java deleted file mode 100644 index 54f9930..0000000 --- a/src/main/java/org/gcube/smartgears/handlers/application/lifecycle/ProfilePublisherImpl.java +++ /dev/null @@ -1,231 +0,0 @@ -package org.gcube.smartgears.handlers.application.lifecycle; - -import static org.gcube.smartgears.handlers.ProfileEvents.published; -import static org.gcube.smartgears.utils.Utils.notEmpty; -import static org.gcube.smartgears.utils.Utils.rethrowUnchecked; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; - -import org.gcube.common.authorization.client.proxy.AuthorizationProxy; -import org.gcube.common.authorization.library.provider.SecurityTokenProvider; -import org.gcube.common.resources.gcore.GCoreEndpoint; -import org.gcube.informationsystem.publisher.ScopedPublisher; -import org.gcube.smartgears.configuration.Mode; -import org.gcube.smartgears.context.application.ApplicationContext; -import org.gcube.smartgears.handlers.ProfilePublisher; -import org.gcube.smartgears.provider.ProviderFactory; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Publishes the current resource profile of the application. - *

- *Distinguishes publication in new scopes ({@link #addTo(List)} from publication updates in existing scopes ({@link #update()}. - * - * - * @author Fabio Simeoni - * - */ -public class ProfilePublisherImpl implements ProfilePublisher { - - private static final Logger log = LoggerFactory.getLogger(ProfilePublisherImpl.class); - - //the underlying IS publisher - private final ScopedPublisher publisher; - - private final ApplicationContext context; - - private AuthorizationProxy authProxy ; - - /** - * Creates an instance for a given application. - * @param context the context of the application - */ - public ProfilePublisherImpl(ApplicationContext context) { - this.context = context; - this.publisher=ProviderFactory.provider().publisherFor(context); - this.authProxy = ProviderFactory.provider().authorizationProxy(); - } - - /** - * Adds for the first time the current resource profile of the application in one or more scopes. - * @param scopes the scopes - */ - @Override - public void addTo(Collection tokens) { - - notEmpty("tokens",tokens); - - GCoreEndpoint profile = context.profile(GCoreEndpoint.class); - - /* TODO: reintroduce it when scope will be removed - //TODO: remove when move to new IS - Collection retainedContexts = new ArrayList(context.container().configuration().allowedContexts()); - retainedContexts.removeAll(profile.scopes().asCollection()); - profile.scopes().asCollection().addAll(retainedContexts); - - - String previousToken = SecurityTokenProvider.instance.get(); - try { - for (String token: tokens){ - log.info("creating profile with token {}", token); - SecurityTokenProvider.instance.set(token); - profile = publisher.create(profile); - SecurityTokenProvider.instance.reset(); - } - }catch (Exception e) { - rethrowUnchecked(e); - } finally{ - SecurityTokenProvider.instance.set(previousToken); - } - */ - - ClassLoader contextCL = Thread.currentThread().getContextClassLoader(); - - log.debug("using context {}",contextCL.getClass().getSimpleName()); - - String previousToken = SecurityTokenProvider.instance.get(); - try{//This classloader set is needed for the jaxb context - if (previousToken==null) - SecurityTokenProvider.instance.set((String)tokens.toArray()[0]); - if (context.container().configuration().mode()!=Mode.root) Thread.currentThread().setContextClassLoader(ProfilePublisherImpl.class.getClassLoader()); - profile = publisher.create(profile, resolveScopesFromTokens(tokens)); - - } catch (Exception e) { - rethrowUnchecked(e); - } finally{ - SecurityTokenProvider.instance.set(previousToken); - if (context.container().configuration().mode()!=Mode.root) Thread.currentThread().setContextClassLoader(contextCL); - } - - sharePublished(profile); - log.debug("shared profile with scopes {}", profile.scopes().asCollection()); - } - - @Override - public void addToAll() { - this.addTo(context.configuration().startTokens()); - } - - - @Override - public void update() { - - - GCoreEndpoint profile = context.profile(GCoreEndpoint.class); - - /* TODO: reintroduce it when scope will be removed - String previousToken = SecurityTokenProvider.instance.get(); - try { - - for (String token: context.configuration().startTokens()){ - SecurityTokenProvider.instance.set(token); - profile = publisher.update(profile); - SecurityTokenProvider.instance.reset(); - } - - } - catch (Exception e) { - rethrowUnchecked(e); - } finally{ - SecurityTokenProvider.instance.set(previousToken); - } - */ - - ClassLoader contextCL = Thread.currentThread().getContextClassLoader(); - - log.debug("using context {}",contextCL.getClass().getSimpleName()); - - String previousToken = SecurityTokenProvider.instance.get(); - try{//This classloader set is needed for the jaxb context - if (previousToken==null) - SecurityTokenProvider.instance.set((String)context.configuration().startTokens().toArray()[0]); - - if (context.container().configuration().mode()!=Mode.root) - Thread.currentThread().setContextClassLoader(ProfilePublisherImpl.class.getClassLoader()); - profile = publisher.update(profile); - - } catch (Exception e) { - rethrowUnchecked(e); - } finally{ - SecurityTokenProvider.instance.set(previousToken); - if (context.container().configuration().mode()!=Mode.root) - Thread.currentThread().setContextClassLoader(contextCL); - } - - sharePublished(profile); - } - - - /** - * Removes the application from one or more scopes. - * @param scopes the scopes - */ - @Override - public void removeFrom(Collection tokens) { - - GCoreEndpoint profile = context.profile(GCoreEndpoint.class); - - /* TODO: reintroduce it when scope will be removed - String previousToken = SecurityTokenProvider.instance.get(); - try { - - for (String token: tokens){ - SecurityTokenProvider.instance.set(token); - profile = publisher.remove(profile); - SecurityTokenProvider.instance.reset(); - } - - } - catch (Exception e) { - - rethrowUnchecked(e); - - } finally{ - SecurityTokenProvider.instance.set(previousToken); - } - */ - - ClassLoader contextCL = Thread.currentThread().getContextClassLoader(); - - log.debug("using context {}",contextCL.getClass().getSimpleName()); - - String previousToken = SecurityTokenProvider.instance.get(); - try{//This classloader set is needed for the jaxb context - if (previousToken==null) - SecurityTokenProvider.instance.set((String)tokens.toArray()[0]); - if (context.container().configuration().mode()!=Mode.root) - Thread.currentThread().setContextClassLoader(ProfilePublisherImpl.class.getClassLoader()); - profile = publisher.remove(profile, resolveScopesFromTokens(tokens)); - - } catch (Exception e) { - rethrowUnchecked(e); - } finally{ - SecurityTokenProvider.instance.set(previousToken); - if (context.container().configuration().mode()!=Mode.root) - Thread.currentThread().setContextClassLoader(contextCL); - } - log.debug("after remove application profile contains scopes {}",profile.scopes().asCollection()); - sharePublished(profile); - } - - - - private void sharePublished(GCoreEndpoint profile) { - context.events().fire(profile,published); - } - - private List resolveScopesFromTokens(Collection tokens){ - List scopes = new ArrayList(tokens.size()); - for (String token: tokens) - try{ - scopes.add(this.authProxy.get(token).getContext()); - }catch (Exception e) { - log.warn("error retrieving token {} , it should never happen",token); - } - return scopes; - } - -} diff --git a/src/main/java/org/gcube/smartgears/handlers/application/request/RequestAccounting.java b/src/main/java/org/gcube/smartgears/handlers/application/request/RequestAccounting.java index 61f7b33..db65ce8 100644 --- a/src/main/java/org/gcube/smartgears/handlers/application/request/RequestAccounting.java +++ b/src/main/java/org/gcube/smartgears/handlers/application/request/RequestAccounting.java @@ -1,16 +1,10 @@ package org.gcube.smartgears.handlers.application.request; -import static org.gcube.smartgears.Constants.called_method_header; - -import javax.xml.bind.annotation.XmlRootElement; - import org.gcube.accounting.datamodel.UsageRecord.OperationResult; import org.gcube.accounting.datamodel.usagerecords.ServiceUsageRecord; import org.gcube.accounting.persistence.AccountingPersistence; import org.gcube.accounting.persistence.AccountingPersistenceFactory; -import org.gcube.common.authorization.library.provider.AuthorizationProvider; -import org.gcube.common.authorization.library.provider.SecurityTokenProvider; -import org.gcube.common.scope.api.ScopeProvider; +import org.gcube.common.security.providers.SecretManagerProvider; import org.gcube.smartgears.Constants; import org.gcube.smartgears.configuration.Mode; import org.gcube.smartgears.context.application.ApplicationContext; @@ -21,100 +15,133 @@ import org.gcube.smartgears.utils.InnerMethodName; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -@XmlRootElement(name = Constants.request_accounting) public class RequestAccounting extends RequestHandler { private static Logger log = LoggerFactory.getLogger(RequestAccounting.class); - private static ThreadLocal startCallThreadLocal = new ThreadLocal(); - - + private static ThreadLocal startCallThreadLocal = new ThreadLocal(); + + private static final String UNKNOWN = "Unknown"; + @Override public String getName() { return Constants.request_accounting; } - + @Override public void handleRequest(RequestEvent e) { - ApplicationContext context = e.context(); - - String calledMethod = e.request().getHeader(called_method_header); - if (calledMethod==null){ - calledMethod = e.request().getRequestURI().substring(e.request().getContextPath().length()); + ApplicationContext appContext = e.context(); + + String context = getContext(appContext); + + if (InnerMethodName.instance.get() == null) { + String calledMethod = e.request().getRequestURI().substring(e.request().getContextPath().length()); if (calledMethod.isEmpty()) calledMethod = "/"; - calledMethod= e.request().getMethod()+" "+calledMethod; + calledMethod = e.request().getMethod() + " " + calledMethod; + InnerMethodName.instance.set(calledMethod); } - InnerMethodName.instance.set(calledMethod); - String caller = AuthorizationProvider.instance.get()!=null? AuthorizationProvider.instance.get().getClient().getId(): "UNKNOWN"; + + String caller = SecretManagerProvider.instance.get() != null + ? SecretManagerProvider.instance.get().getOwner().getId() + : UNKNOWN; startCallThreadLocal.set(System.currentTimeMillis()); - log.info("REQUEST START ON {}:{}({}) CALLED FROM {}@{} IN SCOPE {} ", - context.configuration().name(),context.configuration().serviceClass(), InnerMethodName.instance.get(), - caller, e.request().getRemoteHost(), ScopeProvider.instance.get()); - + + log.info("REQUEST START ON {}:{}({}) CALLED FROM {}@{} IN SCOPE {} ", appContext.configuration().name(), + appContext.configuration().group(), InnerMethodName.instance.get(), caller, + e.request().getRemoteHost(), context); + } @Override public void handleResponse(ResponseEvent e) { - ApplicationContext context = e.context(); - - boolean resetScope = false; - if (ScopeProvider.instance.get()==null && SecurityTokenProvider.instance.get()==null){ - String infrastructure = e.context().container().configuration().infrastructure(); - ScopeProvider.instance.set("/"+infrastructure); - resetScope = true; + ApplicationContext appContext = e.context(); + + try { + + String context = getContext(appContext); + + String caller = SecretManagerProvider.instance.get() != null + ? SecretManagerProvider.instance.get().getOwner().getId() + : UNKNOWN; + String callerQualifier = UNKNOWN; + // retieves caller Ip when there is a proxy + String callerIp = e.request().getHeader("x-forwarded-for"); + if (callerIp == null) + callerIp = e.request().getRemoteHost(); + + boolean success = e.response().getStatus() < 400; + + if (appContext.container().configuration().mode() != Mode.offline) + generateAccounting(caller, callerQualifier, callerIp == null ? UNKNOWN : callerIp, success, context, + appContext); + + long durationInMillis = System.currentTimeMillis() - startCallThreadLocal.get(); + + /* + * Metrics.globalRegistry.timer("smartgears.requests", + * "response",Integer.toString(e.response().getStatus()) , "context", context, + * "result", success?"SUCCEDED":"FAILED", "caller-ip", callerIp, + * "caller-username", caller, "service-class", + * appContext.configuration().serviceClass(), "service-name", + * appContext.configuration().name(), "method", + * InnerMethodName.instance.get()).record(durationInMillis, + * TimeUnit.MILLISECONDS); + */ + + log.info("REQUEST SERVED ON {}:{}({}) CALLED FROM {}@{} IN SCOPE {} {}(CODE {}) IN {} millis", + appContext.configuration().name(), appContext.configuration().group(), + InnerMethodName.instance.get(), caller, callerIp, context, success ? "SUCCEDED" : "FAILED", + e.response().getStatus(), durationInMillis); + + } catch (Exception e1) { + log.error("error on accounting", e); + throw e1; + } finally { + startCallThreadLocal.remove(); + InnerMethodName.instance.reset(); } - - String caller = AuthorizationProvider.instance.get()!=null? AuthorizationProvider.instance.get().getClient().getId(): "UNKNOWN"; - String callerQualifier = AuthorizationProvider.instance.get()!=null? AuthorizationProvider.instance.get().getTokenQualifier(): "UNKNOWN"; - //retieves caller Ip when there is a proxy - String callerIp = e.request().getHeader("x-forwarded-for"); - if(callerIp==null) - callerIp=e.request().getRemoteHost(); - - boolean success = e.response().getStatus()<400; - - if (context.container().configuration().mode()!=Mode.offline) - generateAccounting(caller,callerQualifier,callerIp==null?"UNKNOWN":callerIp , success, context); - - log.info("REQUEST SERVED ON {}:{}({}) CALLED FROM {}@{} IN SCOPE {} {}(CODE {}) IN {} millis", - context.configuration().name(),context.configuration().serviceClass(), InnerMethodName.instance.get(), - caller, callerIp, ScopeProvider.instance.get(), success?"SUCCEDED":"FAILED", e.response().getStatus(), System.currentTimeMillis()-startCallThreadLocal.get()); - startCallThreadLocal.remove(); - InnerMethodName.instance.reset(); - if (resetScope) - ScopeProvider.instance.reset(); + } - void generateAccounting(String caller, String callerQualifier, String remoteHost, boolean success, ApplicationContext context){ - AccountingPersistenceFactory.setFallbackLocation(context.container().persistence().location()); + void generateAccounting(String caller, String callerQualifier, String remoteHost, boolean success, + String gcubeContext, ApplicationContext appContext) { + AccountingPersistenceFactory + .setFallbackLocation(appContext.container().configuration().accountingFallbackLocation()); AccountingPersistence persistence = AccountingPersistenceFactory.getPersistence(); ServiceUsageRecord serviceUsageRecord = new ServiceUsageRecord(); - try{ - + try { + serviceUsageRecord.setConsumerId(caller); serviceUsageRecord.setCallerQualifier(callerQualifier); - serviceUsageRecord.setScope(ScopeProvider.instance.get()); - serviceUsageRecord.setServiceClass(context.configuration().serviceClass()); - serviceUsageRecord.setServiceName(context.configuration().name()); - - serviceUsageRecord.setHost(context.container().configuration().hostname()+":"+context.container().configuration().port()); + serviceUsageRecord.setScope(gcubeContext); + serviceUsageRecord.setServiceClass(appContext.configuration().group()); + serviceUsageRecord.setServiceName(appContext.configuration().name()); + + serviceUsageRecord.setHost(appContext.container().configuration().hostname() + ":" + + appContext.container().configuration().port()); serviceUsageRecord.setCalledMethod(InnerMethodName.instance.get()); serviceUsageRecord.setCallerHost(remoteHost); - serviceUsageRecord.setOperationResult(success?OperationResult.SUCCESS:OperationResult.FAILED); - serviceUsageRecord.setDuration(System.currentTimeMillis()-startCallThreadLocal.get()); + serviceUsageRecord.setOperationResult(success ? OperationResult.SUCCESS : OperationResult.FAILED); + serviceUsageRecord.setDuration(System.currentTimeMillis() - startCallThreadLocal.get()); persistence.account(serviceUsageRecord); - - }catch(Exception ex){ - log.warn("invalid record passed to accounting ",ex); + + } catch (Exception ex) { + log.warn("invalid record passed to accounting ", ex); } } + private String getContext(ApplicationContext appContext) { + String infrastructure = appContext.container().configuration().infrastructure(); + String context = "/" + infrastructure; + if (SecretManagerProvider.instance.get() != null) + context = SecretManagerProvider.instance.get().getContext(); + return context; + } + @Override public String toString() { return getName(); } - - } diff --git a/src/main/java/org/gcube/smartgears/handlers/application/request/RequestContextRetriever.java b/src/main/java/org/gcube/smartgears/handlers/application/request/RequestContextRetriever.java deleted file mode 100644 index e5b984e..0000000 --- a/src/main/java/org/gcube/smartgears/handlers/application/request/RequestContextRetriever.java +++ /dev/null @@ -1,160 +0,0 @@ -package org.gcube.smartgears.handlers.application.request; - -import static org.gcube.common.authorization.client.Constants.authorizationService; -import static org.gcube.smartgears.Constants.scope_header; -import static org.gcube.smartgears.Constants.token_header; -import static org.gcube.smartgears.handlers.application.request.RequestError.internal_server_error; -import static org.gcube.smartgears.handlers.application.request.RequestError.invalid_request_error; - -import java.util.Base64; - -import javax.xml.bind.annotation.XmlRootElement; - -import org.gcube.com.fasterxml.jackson.databind.ObjectMapper; -import org.gcube.common.authorization.client.exceptions.ObjectNotFound; -import org.gcube.common.authorization.library.AuthorizationEntry; -import org.gcube.common.authorization.library.provider.AccessTokenProvider; -import org.gcube.common.authorization.library.provider.AuthorizationProvider; -import org.gcube.common.authorization.library.provider.ClientInfo; -import org.gcube.common.authorization.library.provider.ExternalServiceInfo; -import org.gcube.common.authorization.library.provider.SecurityTokenProvider; -import org.gcube.common.authorization.library.provider.UserInfo; -import org.gcube.common.authorization.library.utils.Caller; -import org.gcube.common.scope.api.ScopeProvider; -import org.gcube.common.scope.impl.ScopeBean; -import org.gcube.smartgears.Constants; -import org.gcube.smartgears.handlers.application.RequestEvent; -import org.gcube.smartgears.handlers.application.RequestHandler; -import org.gcube.smartgears.handlers.application.ResponseEvent; -import org.gcube.smartgears.utils.GcubeJwt; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -@XmlRootElement(name = Constants.request_context_retriever) -public class RequestContextRetriever extends RequestHandler { - - private static Logger log = LoggerFactory.getLogger(RequestContextRetriever.class); - - private static final String BEARER_AUTH_PREFIX ="Bearer"; - private static final String BASIC_AUTH_PREFIX ="Basic"; - - - @Override - public String getName() { - return Constants.request_context_retriever; - } - - @Override - public void handleRequest(RequestEvent call) { - String token = call.request().getParameter(token_header)==null? call.request().getHeader(token_header):call.request().getParameter(token_header); - String scope = call.request().getParameter(scope_header)==null? call.request().getHeader(scope_header):call.request().getParameter(scope_header); - - String authHeader = call.request().getHeader(Constants.authorization_header); - - log.trace("authorization header is {}",authHeader); - log.trace("token header is {}",token); - log.trace("scope header is {}",scope); - - String retrievedUser = null; - String accessToken = null; - if (authHeader!=null && !authHeader.isEmpty()) { - if (authHeader.startsWith(BEARER_AUTH_PREFIX)) - accessToken = authHeader.substring(BEARER_AUTH_PREFIX.length()).trim(); - else if (token==null && authHeader.startsWith(BASIC_AUTH_PREFIX)) { - String basicAuthToken = authHeader.substring(BASIC_AUTH_PREFIX.length()).trim(); - String decodedAuth = new String(Base64.getDecoder().decode(basicAuthToken.getBytes())); - String[] splitAuth = decodedAuth.split(":"); - token = splitAuth[1]; - retrievedUser = splitAuth[0]; - } - } - - //Gives priority to the umaToken - if (accessToken!=null) { - this.retreiveAndSetInfoUmaToken(accessToken, token, call); - } else if (token!=null) - this.retreiveAndSetInfoGcubeToken(token, retrievedUser, call); - else if (scope!=null) - ScopeProvider.instance.set(scope); - - } - - @Override - public void handleResponse(ResponseEvent e) { - SecurityTokenProvider.instance.reset(); - AuthorizationProvider.instance.reset(); - AccessTokenProvider.instance.reset(); - ScopeProvider.instance.reset(); - log.debug("resetting all the Thread local for this call."); - } - - private void retreiveAndSetInfoGcubeToken(String token, String retrievedUser, RequestEvent call){ - log.trace("retrieving context using token {} ", token); - AuthorizationEntry authEntry = null; - try{ - authEntry = authorizationService().get(token); - if (retrievedUser != null && !authEntry.getClientInfo().getId().equals(retrievedUser)) - throw new Exception("user and token owner are not the same"); - }catch(ObjectNotFound onf){ - log.warn("rejecting call to {}, invalid token {}",call.context().name(),token); - invalid_request_error.fire(call.context().name()+" invalid token : "+token); - }catch(Exception e){ - log.error("error contacting authorization service",e); - internal_server_error.fire("error contacting authorization service"); - } - - AuthorizationProvider.instance.set(new Caller(authEntry.getClientInfo(), authEntry.getQualifier())); - SecurityTokenProvider.instance.set(token); - ScopeProvider.instance.set(authEntry.getContext()); - log.info("retrieved request authorization info {} in scope {} ", AuthorizationProvider.instance.get(), authEntry.getContext()); - } - - private void retreiveAndSetInfoUmaToken(String accessToken, String gcubeToken, RequestEvent call){ - log.debug("using UMA token for authorization"); - log.trace("retrieving context using uma token {} ", accessToken); - - AccessTokenProvider.instance.set(accessToken); - parseAccessTokenAndSet(accessToken); - log.info("retrieved request authorization info {} in scope {} ", AuthorizationProvider.instance.get(), ScopeProvider.instance.get()); - } - - private void parseAccessTokenAndSet(String umaToken) { - - String realUmaTokenEncoded = umaToken.split("\\.")[1]; - - String realUmaToken = new String(Base64.getDecoder().decode(realUmaTokenEncoded.getBytes())); - - ObjectMapper mapper = new ObjectMapper(); - - GcubeJwt jwt = null; - try { - jwt = mapper.readValue(realUmaToken, GcubeJwt.class); - }catch(Exception e){ - log.error("error decoding uma token",e); - internal_server_error.fire("error parsing access token"); - } - - ScopeBean scopeBean = null; - try { - scopeBean = new ScopeBean(jwt.getContext()); - }catch(Exception e){ - log.error("error decoding uma token",e); - internal_server_error.fire("invalid context in access token"); - } - - ClientInfo clientInfo; - if (!jwt.isExternalService()) - clientInfo = new UserInfo(jwt.getUsername(), jwt.getRoles(), jwt.getEmail(), jwt.getFirstName(), jwt.getLastName()); - else - clientInfo = new ExternalServiceInfo(jwt.getUsername(), "unknown", jwt.getRoles()); - - log.info("caller type is {}",clientInfo.getType()); - AuthorizationProvider.instance.set(new Caller(clientInfo, "token")); - - ScopeProvider.instance.set(scopeBean.toString()); - - } - - - -} diff --git a/src/main/java/org/gcube/smartgears/handlers/application/request/RequestMetrics.java b/src/main/java/org/gcube/smartgears/handlers/application/request/RequestMetrics.java new file mode 100644 index 0000000..30793be --- /dev/null +++ b/src/main/java/org/gcube/smartgears/handlers/application/request/RequestMetrics.java @@ -0,0 +1,47 @@ +package org.gcube.smartgears.handlers.application.request; + +import java.time.Duration; + +import org.gcube.smartgears.Constants; +import org.gcube.smartgears.handlers.application.RequestEvent; +import org.gcube.smartgears.handlers.application.RequestHandler; +import org.gcube.smartgears.handlers.application.ResponseEvent; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import io.micrometer.core.instrument.Metrics; + +public class RequestMetrics extends RequestHandler { + + private static Logger log = LoggerFactory.getLogger(RequestMetrics.class); + + private static ThreadLocal startCallThreadLocal = new ThreadLocal(); + + private static final String HTTP_REQUEST_METRICS_NAME = "http.server.requests"; + + @Override + public String getName() { + return Constants.request_metrics; + } + + @Override + public boolean isUnfiltrable() { + return true; + } + + @Override + public void handleRequest(RequestEvent e) { + startCallThreadLocal.set(System.currentTimeMillis()); + } + + @Override + public void handleResponse(ResponseEvent e) { + String statusCode = Integer.toString(e.response().getStatus()); + Metrics.globalRegistry.timer(HTTP_REQUEST_METRICS_NAME, "status", statusCode).record(Duration.ofMillis(System.currentTimeMillis() - startCallThreadLocal.get())); + startCallThreadLocal.remove(); + log.debug("metrics for current call saved"); + } + + + +} diff --git a/src/main/java/org/gcube/smartgears/handlers/application/request/RequestValidator.java b/src/main/java/org/gcube/smartgears/handlers/application/request/RequestValidator.java index a35ec9a..8135571 100644 --- a/src/main/java/org/gcube/smartgears/handlers/application/request/RequestValidator.java +++ b/src/main/java/org/gcube/smartgears/handlers/application/request/RequestValidator.java @@ -1,47 +1,39 @@ package org.gcube.smartgears.handlers.application.request; -import static org.gcube.common.authorization.client.Constants.authorizationService; +import static org.gcube.smartgears.Constants.token_header; import static org.gcube.smartgears.handlers.application.request.RequestError.application_failed_error; import static org.gcube.smartgears.handlers.application.request.RequestError.application_unavailable_error; import static org.gcube.smartgears.handlers.application.request.RequestError.invalid_request_error; -import java.util.Collections; -import java.util.List; +import java.util.Set; -import javax.xml.bind.annotation.XmlAttribute; -import javax.xml.bind.annotation.XmlRootElement; - -import org.gcube.common.authorization.library.PolicyUtils; -import org.gcube.common.authorization.library.policies.Policy; -import org.gcube.common.authorization.library.policies.User2ServicePolicy; -import org.gcube.common.authorization.library.policies.UserEntity; -import org.gcube.common.authorization.library.provider.AccessTokenProvider; -import org.gcube.common.authorization.library.provider.AuthorizationProvider; -import org.gcube.common.authorization.library.provider.SecurityTokenProvider; -import org.gcube.common.authorization.library.provider.ServiceIdentifier; -import org.gcube.common.scope.api.ScopeProvider; -import org.gcube.common.scope.impl.ScopeBean; -import org.gcube.common.scope.impl.ScopeBean.Type; +import org.gcube.common.keycloak.KeycloakClient; +import org.gcube.common.keycloak.KeycloakClientException; +import org.gcube.common.keycloak.KeycloakClientFactory; +import org.gcube.common.security.ContextBean; +import org.gcube.common.security.ContextBean.Type; +import org.gcube.common.security.providers.SecretManagerProvider; +import org.gcube.common.security.secrets.GCubeSecret; +import org.gcube.common.security.secrets.Secret; +import org.gcube.common.security.secrets.UmaTokenSecret; import org.gcube.smartgears.Constants; import org.gcube.smartgears.configuration.Mode; import org.gcube.smartgears.configuration.container.ContainerConfiguration; import org.gcube.smartgears.context.application.ApplicationContext; import org.gcube.smartgears.handlers.application.RequestEvent; import org.gcube.smartgears.handlers.application.RequestHandler; -import org.gcube.smartgears.utils.Utils; +import org.gcube.smartgears.handlers.application.ResponseEvent; +import org.gcube.smartgears.security.SimpleCredentials; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -@XmlRootElement(name = Constants.request_validation) public class RequestValidator extends RequestHandler { - @XmlAttribute(required=false, name="oauth") - @Deprecated - boolean oauthCompatibility = false; - private static Logger log = LoggerFactory.getLogger(RequestValidator.class); - private ApplicationContext context; + private static final String BEARER_AUTH_PREFIX ="Bearer"; + + private ApplicationContext appContext; @Override public String getName() { @@ -53,27 +45,31 @@ public class RequestValidator extends RequestHandler { log.trace("executing request validator ON REQUEST"); - log.trace("accessToken is null? {} \nGcubeToken is null ? {} \nscope rpvideris null? {}", - AccessTokenProvider.instance.get()==null, - SecurityTokenProvider.instance.get()==null, - ScopeProvider.instance.get()==null); - - context = call.context(); + appContext = call.context(); + + SecretManagerProvider.instance.set(getSecret(call)); validateAgainstLifecycle(call); rejectUnauthorizedCalls(call); - if (context.container().configuration().mode()!=Mode.offline) { + if (appContext.container().configuration().mode()!=Mode.offline) { validateScopeCall(); - validatePolicy(ScopeProvider.instance.get(), call); + validatePolicy(call); } } + @Override + public void handleResponse(ResponseEvent e) { + log.debug("resetting all the Thread local for this call."); + SecretManagerProvider.instance.reset(); + } + + private void validateAgainstLifecycle(RequestEvent call) { - switch(context.lifecycle().state()) { + switch(appContext.lifecycle().state()) { case stopped : application_unavailable_error.fire(); break; @@ -85,36 +81,36 @@ public class RequestValidator extends RequestHandler { //nothing to do, but avoids warnings } - } private void validateScopeCall() { - String scope = ScopeProvider.instance.get(); + String context = SecretManagerProvider.instance.get().getContext(); - if (scope == null) { - log.warn("rejecting unscoped call to {}",context.name()); + if (context == null) { + log.warn("rejecting unscoped call to {}",appContext.name()); invalid_request_error.fire("call is unscoped"); } - ScopeBean bean = new ScopeBean(scope); + ContextBean bean = new ContextBean(context); - ContainerConfiguration conf = context.container().configuration(); - if (!conf.allowedContexts().contains(scope) && - !(conf.authorizeChildrenContext() && bean.is(Type.VRE) && conf.allowedContexts().contains(bean.enclosingScope().toString()) ) ) { - log.warn("rejecting call to {} in invalid context {}, allowed context are {}",context.name(),scope,context.container().configuration().allowedContexts()); - invalid_request_error.fire(context.name()+" cannot be called in scope "+scope); + ContainerConfiguration conf = appContext.container().configuration(); + Set allowedContexts =appContext.authorizationProvider().getContexts(); + if (!allowedContexts.contains(context) && + !(conf.authorizeChildrenContext() && bean.is(Type.VRE) + && allowedContexts.contains(bean.enclosingScope().toString()) ) ) { + log.warn("rejecting call to {} in invalid context {}, allowed context are {}",appContext.name(),context,allowedContexts); + invalid_request_error.fire(appContext.name()+" cannot be called in scope "+context); } } private void rejectUnauthorizedCalls(RequestEvent call){ - String token = SecurityTokenProvider.instance.get(); - String accessToken = AccessTokenProvider.instance.get(); - - if (token == null && accessToken==null){ - log.warn("rejecting call to {}, authorization required",context.name(),token); - RequestError.request_not_authorized_error.fire(context.name()+": authorization required"); + Secret secret = SecretManagerProvider.instance.get(); + + if (secret == null){ + log.warn("rejecting call to {}, authorization required",appContext.name()); + RequestError.request_not_authorized_error.fire(appContext.name()+": authorization required"); } } @@ -123,45 +119,39 @@ public class RequestValidator extends RequestHandler { return getName(); } - private void validatePolicy(String scope, RequestEvent call){ - log.info("accessing policy validator in scope {} ", scope); + private void validatePolicy(RequestEvent call){ + //TODO: must be re-thought + } - ServiceIdentifier serviceIdentifier = Utils.getServiceInfo(call.context()).getServiceIdentifier(); + private Secret getSecret(RequestEvent call){ + String token = call.request().getParameter(token_header)==null? call.request().getHeader(token_header):call.request().getParameter(token_header); + String authHeader = call.request().getHeader(Constants.authorization_header); - String previousToken = SecurityTokenProvider.instance.get(); - try { - String serviceToken = context.configuration().startTokens().stream().findFirst().get(); - SecurityTokenProvider.instance.set(serviceToken); - String callerId = AuthorizationProvider.instance.get().getClient().getId(); - List policies = Collections.emptyList(); + log.trace("authorization header is {}",authHeader); + log.trace("token header is {}", token); + + log.info("d4s-user set to {} ", call.request().getHeader("d4s-user")); + + String umaToken = null; + if (authHeader!=null && !authHeader.isEmpty()) + if (authHeader.startsWith(BEARER_AUTH_PREFIX)) + umaToken = authHeader.substring(BEARER_AUTH_PREFIX.length()).trim(); + + Secret secret = null; + if (umaToken!=null) { + secret = new UmaTokenSecret(umaToken); + SimpleCredentials credentials = (SimpleCredentials)appContext.authorizationProvider().getCredentials(); + KeycloakClient client = KeycloakClientFactory.newInstance(); try { - policies = authorizationService().getPolicies(scope); - }catch (Exception e) { - log.error("error contacting authorization services for policies"); + if(!client.isAccessTokenVerified(secret.getContext(), credentials.getClientID(), credentials.getSecret(), umaToken)) + RequestError.request_not_authorized_error.fire("access token verification error"); + }catch (KeycloakClientException e) { + RequestError.internal_server_error.fire("error contacting keycloak client", e); } - - for (Policy policy: policies) { - log.debug("policy: {}", policy.getPolicyAsString() ); - - if (PolicyUtils.isPolicyValidForClient(policy.getServiceAccess(), serviceIdentifier )) { - boolean toReject = false; - UserEntity entity = (((User2ServicePolicy) policy).getEntity()); - if (entity.getIdentifier()!=null) - toReject = entity.getIdentifier().equals(callerId); - else if (entity.getExcludes().isEmpty()) - toReject = true; - else toReject = !entity.getExcludes().contains(callerId); - if (toReject) { - log.error("rejecting call to {} : {} is not allowed to contact the service ",context.name(), callerId); - RequestError.request_not_authorized_error.fire("rejecting call to "+context.name()+" for polices: "+callerId+" is not allowed to contact the service: "+serviceIdentifier.getServiceName() ); - } - } - - } - }finally { - SecurityTokenProvider.instance.set(previousToken); - } + } else if (token!=null && !token.isEmpty()) + secret = new GCubeSecret(token); + return secret; } diff --git a/src/main/java/org/gcube/smartgears/handlers/container/lifecycle/AccountingManager.java b/src/main/java/org/gcube/smartgears/handlers/container/lifecycle/AccountingManager.java index a879731..019e2ab 100644 --- a/src/main/java/org/gcube/smartgears/handlers/container/lifecycle/AccountingManager.java +++ b/src/main/java/org/gcube/smartgears/handlers/container/lifecycle/AccountingManager.java @@ -5,8 +5,6 @@ package org.gcube.smartgears.handlers.container.lifecycle; import static org.gcube.smartgears.Constants.accounting_management; -import javax.xml.bind.annotation.XmlRootElement; - import org.gcube.accounting.persistence.AccountingPersistenceFactory; import org.gcube.smartgears.handlers.container.ContainerHandler; import org.gcube.smartgears.handlers.container.ContainerLifecycleEvent; @@ -16,7 +14,6 @@ import org.slf4j.LoggerFactory; /** * @author Luca Frosini (ISTI - CNR) */ -@XmlRootElement(name = accounting_management) public class AccountingManager extends ContainerHandler { private static Logger logger = LoggerFactory.getLogger(AccountingManager.class); diff --git a/src/main/java/org/gcube/smartgears/handlers/container/lifecycle/ContainerProfileManager.java b/src/main/java/org/gcube/smartgears/handlers/container/lifecycle/ContainerProfileManager.java new file mode 100644 index 0000000..58440b0 --- /dev/null +++ b/src/main/java/org/gcube/smartgears/handlers/container/lifecycle/ContainerProfileManager.java @@ -0,0 +1,220 @@ +package org.gcube.smartgears.handlers.container.lifecycle; + +import static java.util.concurrent.TimeUnit.SECONDS; +import static org.gcube.common.events.Observes.Kind.critical; +import static org.gcube.common.events.Observes.Kind.resilient; +import static org.gcube.smartgears.Constants.profile_management; +import static org.gcube.smartgears.handlers.ProfileEvents.addToContext; +import static org.gcube.smartgears.handlers.ProfileEvents.changed; +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 java.util.Collections; +import java.util.List; +import java.util.concurrent.ScheduledFuture; + +import org.gcube.common.events.Observes; +import org.gcube.smartgears.configuration.Mode; +import org.gcube.smartgears.context.Property; +import org.gcube.smartgears.context.container.ContainerContext; +import org.gcube.smartgears.handlers.container.ContainerHandler; +import org.gcube.smartgears.handlers.container.ContainerLifecycleEvent; +import org.gcube.smartgears.lifecycle.container.ContainerLifecycle; +import org.gcube.smartgears.lifecycle.container.ContainerState; +import org.gcube.smartgears.provider.ProviderFactory; +import org.gcube.smartgears.publishing.Publisher; +import org.gcube.smartgears.utils.Utils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * + * Manages the resource profile of the application. + *

+ * + * The manager: + * + *

    + *
  • creates the profile when the application starts for the first time; + *
  • loads the profile when the application restarts; + *
  • publishes the profile when the application becomes active, and at any + * lifecycle change thereafter; + *
  • stores the profile locally after each publication; + *
+ * + * @author Fabio Simeoni + * @see ProfileBuilder + * @see ProfilePublisherImpl + */ +public class ContainerProfileManager extends ContainerHandler { + + Logger log = LoggerFactory.getLogger(ContainerProfileManager.class); + + private ContainerContext context; + private ScheduledFuture periodicUpdates; + private static final String PUBLISHED_PROP = "published"; + private List publishers; + + + @Override + public void onStart(ContainerLifecycleEvent.Start e) { + + context = e.context(); + + activated(); + + // note we don't fire profile events, but wait for the final startup + // outcome which + // will result in a state change. only then we publish and store the + // profile + // this avoids the redundancy and performance penalty of storing and + // publishing multiple + // times in rapid succession (which would be correct). Revise if proves + // problematic in corner + // cases. + + } + + + private void activated(){ + publishers = context.configuration().mode()!=Mode.offline? + ProviderFactory.provider().publishers(): + Collections.emptyList(); + registerObservers(); + schedulePeriodicUpdates(); + } + + private void registerObservers() { + context.events().subscribe(new Object() { + @Observes({ activation, part_activation, shutdown, stop, failure }) + void onChanged(ContainerLifecycle lc) { + + // since we do not know the observers, they will deal with failures and their consequences + // any that comes back will be logged in this event thread + context.events().fire(context, changed); + } + + @Observes(value = changed, kind = critical) + void publishAfterChange(ContainerContext context) { + log.info("Publish after profile Change event called"); + //if we've failed before first publication do not try to publish + //(we may well have failed there) + if (!context.properties().contains(PUBLISHED_PROP)) { + context.properties().add(new Property(PUBLISHED_PROP, true)); + log.info("publishing container for the first time"); + if (context.lifecycle().state() != ContainerState.failed) { + publishers.forEach(p -> { + try { + p.create(context, + context.authorizationProvider().getContexts()); + }catch (Exception e) { + log.error("cannot publish container for first time with publisher type {} (see details)", p.getClass().getCanonicalName(), e); + } + }); + } + } + else + publishers.forEach(p -> { + try { + p.update(context); + }catch (Exception e) { + log.error("cannot publish container with publisher type {} (see details)", p.getClass().getCanonicalName(), e); + } + }); + + } + + @Observes(value = addToContext) + void addTo(String scope) { + log.info("add_to_context event arrived in container"); + for (Publisher publisher: publishers) + try { + log.trace("publishing container within new scope"); + publisher.create(context, + Collections.singleton(scope)); + + }catch (Exception e) { + + log.error("cannot add container to {} with publisher type {} (see details)",scope, publisher.getClass().getCanonicalName(), e); + + // since we've failed no published event is fired and profile + // will not be stored. + // we do it manually to ensure we leave some local trace of the + // changed profile. + //TODO: CHECK --- store(profile); + } + + } + + @Observes(value = removeFromContext) + void removeFrom(String scope) { + log.info("remove_from_context event arrived in container"); + for (Publisher publisher: publishers) + try { + log.trace("unpublishing container from context {}", scope); + publisher.remove(context, + Collections.singleton(scope)); + + }catch (Exception e) { + + log.error("cannot remove container from {} with publisher type {} (see details)",scope, publisher.getClass().getCanonicalName(), e); + + // since we've failed no published event is fired and profile + // will not be stored. + // we do it manually to ensure we leave some local trace of the + // changed profile. + //TODO: CHECK --- store(profile); + } + } + }); + } + + + private void schedulePeriodicUpdates() { + // register to cancel updates + context.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, part_activation }, kind = resilient) + synchronized void restartPeriodicUpdates(ContainerLifecycle lc) { + //already running + if (periodicUpdates!=null) + return; + if (lc.state()==active) + log.info("scheduling periodic updates of container profile"); + else + log.info("resuming periodic updates of container profile"); + final Runnable updateTask = new Runnable() { + public void run() { + context.events().fire(context,changed); + } + }; + periodicUpdates = Utils.scheduledServicePool.scheduleAtFixedRate(updateTask, 3, context.configuration() + .publicationFrequency(), SECONDS); + } + @Observes(value = { stop, failure, shutdown }, kind = resilient) + synchronized void cancelPeriodicUpdates(ContainerLifecycle ignore) { + if (periodicUpdates != null){ + log.trace("stopping periodic updates of container profile"); + try { + periodicUpdates.cancel(true); + periodicUpdates=null; + } + catch(Exception e) { + log.warn("could not stop periodic updates of container profile",e); + } + } + } + }); + } + @Override + public String toString() { + return profile_management; + } +} + diff --git a/src/main/java/org/gcube/smartgears/handlers/container/lifecycle/ProfileBuilder.java b/src/main/java/org/gcube/smartgears/handlers/container/lifecycle/ProfileBuilder.java deleted file mode 100644 index 3f1ac67..0000000 --- a/src/main/java/org/gcube/smartgears/handlers/container/lifecycle/ProfileBuilder.java +++ /dev/null @@ -1,375 +0,0 @@ -package org.gcube.smartgears.handlers.container.lifecycle; - -import java.io.BufferedReader; -import java.io.File; -import java.io.FileReader; -import java.io.IOException; -import java.io.InputStreamReader; -import java.io.Reader; -import java.math.BigDecimal; -import java.net.InetAddress; -import java.net.UnknownHostException; -import java.nio.file.Files; -import java.nio.file.Paths; -import java.util.ArrayList; -import java.util.Calendar; -import java.util.HashMap; -import java.util.Map; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import org.gcube.common.resources.gcore.HostingNode; -import org.gcube.common.resources.gcore.HostingNode.Profile.NodeDescription.GHNType; -import org.gcube.common.resources.gcore.HostingNode.Profile.NodeDescription.Processor; -import org.gcube.common.resources.gcore.HostingNode.Profile.NodeDescription.Variable; -import org.gcube.common.resources.gcore.utils.Group; -import org.gcube.smartgears.configuration.container.ContainerConfiguration; -import org.gcube.smartgears.configuration.library.SmartGearsConfiguration; -import org.gcube.smartgears.context.container.ContainerContext; -import org.gcube.smartgears.provider.ProviderFactory; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * @author Fabio Simeoni - * @author Luca Frosini (ISTI - CNR) - * - */ -public class ProfileBuilder { - - private static Logger log = LoggerFactory.getLogger(ProfileBuilder.class); - - private ContainerContext context; - - public ProfileBuilder(ContainerContext context) { - this.context = context; - } - - public HostingNode create() { - - HostingNode node = new HostingNode(); - - ContainerConfiguration cfg = context.configuration(); - - node.newProfile().infrastructure(cfg.infrastructure()); - - addSiteTo(node); - - String ip = "not resolved"; - try { - ip = InetAddress.getLocalHost().getHostAddress(); - } catch (UnknownHostException e) { - log.warn("unable to detect the IP address of the host"); - } - - node.profile().newDescription().activationTime(Calendar.getInstance()).name(cfg.hostname() + ":" + cfg.port()); - - node.profile().description().networkAdapters().add().mtu(0).name("local-adapter").ipAddress(ip).inboundIP("") - .outboundIP(""); - - node.profile().description().newOperatingSystem().name(System.getProperty("os.name")) - .version(System.getProperty("os.version")).release(""); - - node.profile().description().newArchitecture().platformType(System.getProperty("os.arch")).smpSize(0) - .smtSize(0); - - ArrayList> info = cpuInfo(); - - Group processors = node.profile().description().processors(); - - for (HashMap map : info) - - processors.add().bogomips(new BigDecimal(map.get("bogomips"))) - .clockSpeedMhz(new BigDecimal(map.get("cpu_MHz"))).family(map.get("cpu_family")) - .modelName(map.get("model_name")).model(map.get("model")).vendor(map.get("vendor_id")) - .cacheL1(new Integer(map.get("cache_size"))).cacheL1D(0).cacheL1I(0).cacheL2(0); - - addVariablesTo(node); - - update(node,false); - - node.profile().description().type(GHNType.Static); - // String type = (String) context.getProperty(GHNContext.GHN_TYPE, false); - // if (type.compareToIgnoreCase(Type.DYNAMIC.toString()) == 0) description.setType(Description.Type.Dynamic); - // else if (type.compareToIgnoreCase(Type.STATIC.toString()) == 0) description.setType(Description.Type.Static); - // else if (type.compareToIgnoreCase(Type.SELFCLEANING.toString()) == 0) - // description.setType(Description.Type.Selfcleaning); - // - // file system - node.profile().description().localFileSystems().add().name("").type("").readOnly(false) - .root(cfg.persistence().location()); - - return node; - } - - @SuppressWarnings("all") - private ArrayList> cpuInfo() { - - ArrayList> map = new ArrayList>(); - - File file = new File("/proc/cpuinfo"); - - if (!file.exists()) { - log.warn("cannot acquire CPU info (no /proc/cpuinfo)"); - return map; - } - - BufferedReader input = null; - - try { - input = new BufferedReader(new FileReader(file)); - - String line = null; - - HashMap currentProcessor = null; - - while ((line = input.readLine()) != null) { - - if ((line.startsWith("processor"))) { // add the current processor to the map - - if (currentProcessor != null) - map.add((HashMap) currentProcessor.clone()); - - currentProcessor = new HashMap(); - } - - try { - if (line.contains("vendor_id")) - currentProcessor.put("vendor_id", line.split(":")[1].trim()); - } catch (Exception ex) { - } - try { - if (line.contains("cpu family")) - currentProcessor.put("cpu_family", line.split(":")[1].trim()); - } catch (Exception ex) { - } - try { - if ((line.contains("model\t")) || (line.contains("model\b"))) - currentProcessor.put("model", line.split(":")[1].trim()); - } catch (Exception ex) { - } - try { - if (line.contains("model name")) - currentProcessor.put("model_name", line.split(":")[1].trim()); - } catch (Exception ex) { - } - try { - if (line.contains("cpu MHz")) - currentProcessor.put("cpu_MHz", line.split(":")[1].trim()); - } catch (Exception ex) { - } - try { - if (line.contains("cache size")) - currentProcessor.put("cache_size", line.split(":")[1].trim().split(" ")[0]); - } catch (Exception ex) { - } - try { - if (line.contains("bogomips")) - currentProcessor.put("bogomips", line.split(":")[1].trim()); - } catch (Exception ex) { - } - } - - if (currentProcessor != null) - map.add(currentProcessor); - - } catch (Exception e) { - - log.warn("unable to acquire CPU info", e); - - } finally { - - if (input != null) - try { - input.close(); - } catch (IOException e) { - log.warn("unable to close stream", e); - } - } - return map; - } - - private long getFreeSpace() { - long free = 0; - try { - free = Files.getFileStore(Paths.get(context.configuration().persistence().location())).getUsableSpace()/1024; - } catch (IOException ioe) { - log.warn("unable to detect the free space on the disk", ioe); - } - return free; - } - - public void update(HostingNode node,boolean onLoad) { - - ContainerConfiguration cfg = context.configuration(); - - if (onLoad) { - - log.info("updating ghn profile"); - - node.profile().description().activationTime(Calendar.getInstance()).name(cfg.hostname() + ":" + cfg.port()); - - addVariablesTo(node); - - addSiteTo(node); - - } - - node.profile().description().status(context.lifecycle().state().remoteForm()); - - Map mem = memoryUsage(); - - node.profile().description().newMainMemory().ramAvailable(mem.get("MemoryAvailable")) - .ramSize(mem.get("MemoryTotalSize")).virtualAvailable(mem.get("VirtualAvailable")) - .virtualSize(mem.get("VirtualSize")); - - node.profile().description().localAvailableSpace(getFreeSpace()); - - node.profile().description().uptime(uptime()); - - node.profile().description().lastUpdate(Calendar.getInstance()); - - Map loads = loadStatistics(); - - node.profile().description().newLoad().lastMin(loads.get("1min") == null ? 0 : loads.get("1min")) - .last5Mins(loads.get("5mins") == null ? 0 : loads.get("5mins")) - .last15Mins(loads.get("15mins") == null ? 0 : loads.get("15mins")); - - } - - private void addSiteTo(HostingNode node) { - - ContainerConfiguration cfg = context.configuration(); - - node.profile().newSite().country(cfg.site().country()).location(cfg.site().location()) - .latitude(cfg.site().latitude()).longitude(cfg.site().longitude()).domain(domainIn(cfg.hostname())); - } - - private void addVariablesTo(HostingNode node) { - - ContainerConfiguration cfg = context.configuration(); - - Group variables = node.profile().description().environmentVariables(); - - // Cleaning variables to avoid duplicates - variables.removeAll(node.profile().description().environmentVariables()); - - Map map = new HashMap(); - map.putAll(cfg.properties()); - map.putAll(System.getenv()); - - 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; - variables.add().keyAndValue(entry.getKey(), entry.getValue()); - } - - /* The following code is useless can be removed - Map envvars = new HashMap(); - for (String varname : envvars.keySet()) { - - // a bit of filtering - if ((varname.compareToIgnoreCase("CLASSPATH") == 0) || (varname.compareToIgnoreCase("PATH") == 0) - || (varname.contains("SSH")) || (varname.contains("MAIL")) - || (varname.compareToIgnoreCase("LS_COLORS") == 0)) - continue; - - variables.add().keyAndValue(varname, envvars.get(varname)); - } - */ - - - String osVersion = System.getProperty("os.name"); - if(osVersion.compareToIgnoreCase("Linux")==0) { - LinuxDistributionInfo linuxDistributionInfo = new LinuxDistributionInfo(); - Map info = linuxDistributionInfo.getInfo(); - for(String key : info.keySet()) { - variables.add().keyAndValue(key, info.get(key)); - } - } - - variables.add().keyAndValue("Java", System.getProperty("java.version")); - - SmartGearsConfiguration config = ProviderFactory.provider().smartgearsConfiguration(); - variables.add().keyAndValue("SmartGears",config.version()); - - variables.add().keyAndValue("ghn-update-interval-in-secs", String.valueOf(cfg.publicationFrequency())); - - } - - public String uptime() { - String lines = "", linetemp = null; - try { - Process p = Runtime.getRuntime().exec("uptime"); - p.waitFor(); - BufferedReader input = new BufferedReader(new InputStreamReader(p.getInputStream())); - while ((linetemp = input.readLine()) != null) - lines += linetemp; - input.close(); - p.destroy(); - lines = lines.split(",")[0].split("up")[1].trim(); - } catch (Exception e) { - log.warn("unable to detect the uptime of this machine", e); - lines = "unable to detect"; - } - return lines; - } - - public Map loadStatistics() { - - Map result = new HashMap(); - try { - File loadadv = new File("/proc/loadavg"); - if (loadadv.exists()) { - Reader reader = new FileReader(loadadv); - int c; - StringBuilder content = new StringBuilder(); - while ((c = reader.read()) != -1) - content.append((char) c); - reader.close(); - Pattern p = Pattern.compile("^(.*?)\\s{1}(.*?)\\s{1}(.*?)\\s{1}(.*)$"); - Matcher matcher = p.matcher(content.toString()); - if ((matcher.matches()) && (matcher.groupCount() > 3)) { - result.put("1min", new Double(matcher.group(1))); - result.put("5mins", new Double(matcher.group(2))); - result.put("15mins", new Double(matcher.group(3).split("\\s")[0])); - } - } - } catch (Exception ioe) { - log.warn("unable to detect the load values of this machine", ioe); - } - return result; - } - - @SuppressWarnings("all") - public Map memoryUsage() { - Map map = new HashMap(); - java.lang.management.OperatingSystemMXBean mxbean = java.lang.management.ManagementFactory - .getOperatingSystemMXBean(); - com.sun.management.OperatingSystemMXBean sunmxbean = (com.sun.management.OperatingSystemMXBean) mxbean; - long freeMemory = sunmxbean.getFreePhysicalMemorySize() / 1048576; // in MB - long availableMemory = sunmxbean.getTotalPhysicalMemorySize() / 1048576; // in MB - map.put("MemoryAvailable", freeMemory); - map.put("MemoryTotalSize", availableMemory); - long ramVirtualAvailable = Runtime.getRuntime().freeMemory() / 1048576; // in MB - long ramVirtualSize = Runtime.getRuntime().totalMemory() / 1048576; // in MB - map.put("VirtualAvailable", ramVirtualAvailable); - map.put("VirtualSize", ramVirtualSize); - return map; - } - - private String domainIn(String hostname) { - Pattern pattern = Pattern.compile("([0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3})"); - java.util.regex.Matcher regexMatcher = pattern.matcher(hostname); - if (regexMatcher.matches()) //it's an IP address, nothing to trim - return hostname; - String[] tokens = hostname.split("\\."); - if (tokens.length < 2) - return hostname; - else - return tokens[tokens.length-2]+ "." + tokens[tokens.length-1]; - } -} diff --git a/src/main/java/org/gcube/smartgears/handlers/container/lifecycle/ProfileManager.java b/src/main/java/org/gcube/smartgears/handlers/container/lifecycle/ProfileManager.java deleted file mode 100644 index ad9a450..0000000 --- a/src/main/java/org/gcube/smartgears/handlers/container/lifecycle/ProfileManager.java +++ /dev/null @@ -1,294 +0,0 @@ -package org.gcube.smartgears.handlers.container.lifecycle; - -import static java.util.concurrent.TimeUnit.SECONDS; -import static org.gcube.common.events.Observes.Kind.critical; -import static org.gcube.common.events.Observes.Kind.resilient; -import static org.gcube.smartgears.Constants.container_profile_property; -import static org.gcube.smartgears.Constants.profile_management; -import static org.gcube.smartgears.handlers.ProfileEvents.addToContext; -import static org.gcube.smartgears.handlers.ProfileEvents.changed; -import static org.gcube.smartgears.handlers.ProfileEvents.published; -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 java.util.Collections; -import java.util.concurrent.ScheduledFuture; - -import javax.xml.bind.annotation.XmlRootElement; - -import org.gcube.common.events.Observes; -import org.gcube.common.resources.gcore.HostingNode; -import org.gcube.smartgears.configuration.Mode; -import org.gcube.smartgears.context.Property; -import org.gcube.smartgears.context.container.ContainerContext; -import org.gcube.smartgears.handlers.OfflineProfilePublisher; -import org.gcube.smartgears.handlers.ProfilePublisher; -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.utils.Utils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * - * Manages the resource profile of the container. - *

- * - * The manager: - * - *

    - *
  • creates the profile when the container starts for the first time; - *
  • loads the profile when the container restarts; - *
  • publishes the profile when the container becomes active, and at any lifecycle change thereafter; - *
  • stores the profile locally after each publication; - *
- * - * @author Fabio Simeoni - * @see ProfileBuilder - */ -@XmlRootElement(name = profile_management) -public class ProfileManager extends ContainerHandler { - - private static Logger log = LoggerFactory.getLogger(ProfileManager.class); - - private ContainerContext context; - - private ProfileBuilder builder; - private ProfilePublisher publisher; - - - private ScheduledFuture periodicUpdates; - - @Override - public void onStart(Start e) { - - context = e.context(); - builder = new ProfileBuilder(context); - - activated(); - - // note we don't fire profile events, but wait for the final startup response which - // will result in a state change. only then we publish and store the profile - // this avoids the redundancy and performance penalty of storing and publishing multiple - // times in rapid succession (which would be correct). Revise if proves problematic in corner - // cases. - - } - - private void activated(){ - HostingNode profile = loadOrCreateProfile(); - - share(profile); - - publisher = context.configuration().mode()!=Mode.offline? - new ProfilePublisherImpl(context): - new OfflineProfilePublisher(); - - registerObservers(); - - schedulePeriodicUpdates(); - } - - private void registerObservers() { - - context.events().subscribe(new Object() { - - @Observes({ activation, part_activation, shutdown, stop, failure }) - void onChanged(ContainerLifecycle lc) { - - HostingNode profile = context.profile(HostingNode.class); - - profile.profile().description().status(lc.state().remoteForm()); - - // since we do not know the observers, they will deal with failures and their consequences - // any that comes back will be logged in this event thread - context.events().fire(profile, changed); - - } - - - @Observes(value = published) - void shareAfterPublish(HostingNode profile) { - - share(profile); // publish may produce a new profile instance - - } - - @Observes(value = changed, kind = critical) - void publishAfterChange(HostingNode profile) { - log.info("Publish after profile Change event called"); - publish(profile); // if successful, triggers share and store. - - } - - @Observes(value = addToContext) - void addTo(String token) { - try { - log.trace("publishing container with new token"); - publisher.addTo(Collections.singleton(token)); - publisher.update(); - }catch (Exception e) { - - log.error("cannot add token {} (see details)",token, e); - - // since we've failed no published event is fired and profile - // will not be stored. - // we do it manually to ensure we leave some local trace of the - // changed profile. - //TODO: CHECK --- store(profile); - } - - } - - @Observes(value = removeFromContext) - void removeFrom(String token) { - try { - log.trace("unpublishing container with new token"); - publisher.removeFrom(Collections.singleton(token)); - publisher.update(); - }catch (Exception e) { - - log.error("cannot remove token {} (see details)",token, e); - - // since we've failed no published event is fired and profile - // will not be stored. - // we do it manually to ensure we leave some local trace of the - // changed profile. - //TODO: CHECK --- store(profile); - } - - } - }); - } - - private HostingNode loadOrCreateProfile() { - - return createProfile(); - - } - - private void share(HostingNode profile) { - - log.trace("sharing container profile"); - context.properties().add(new Property(container_profile_property, profile)); - } - - private HostingNode createProfile() { - - log.info("creating container profile"); - - try { - HostingNode node = builder.create(); - node.setId(context.id()); - return node; - } catch (Throwable e) { - - // this is a critical startup failure: it will fail the application - throw new RuntimeException("cannot create container profile", e); - - } - - } - - private void publish(HostingNode profile) { - - //ContainerConfiguration configuration = context.configuration(); - - // first-publication vs. routine publication: when we delete scopes let's make sure there is - // at least one left of it will be re-triggered - boolean firstPublication = profile.scopes().isEmpty(); - - try { - - if (firstPublication) - publisher.addToAll(); - else - publisher.update(); - - } catch (Exception e) { - - log.error("cannot publish container (see details)", e); - - // since we've failed no published event is fired and profile will not be stored. - // we do it manually to ensure we leave some local trace of the changed profile. - //store(profile); - - } - } - - private void schedulePeriodicUpdates() { - - // register to cancel updates - context.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, part_activation }, kind = resilient) - synchronized void restartPeriodicUpdates(ContainerLifecycle lc) { - - //already running - if (periodicUpdates!=null) - return; - - if (lc.state()==active) - log.info("scheduling periodic updates of container profile"); - - else - log.info("resuming periodic updates of container profile"); - - final Runnable updateTask = new Runnable() { - public void run() { - HostingNode profile = context.profile(HostingNode.class); - - try { - builder.update(profile, false); - } - catch(Exception e) { - //we may fail in the update of the profile - log.error("cannot complete periodic update of container profile",e); - } - - //if handling of event generates failures these will be reported - //for resilience we do not fail the application - log.trace("firing change event on container profile"); - context.events().fire(profile,changed); - } - }; - - periodicUpdates = Utils.scheduledServicePool.scheduleAtFixedRate(updateTask, 3, context.configuration() - .publicationFrequency(), SECONDS); - - } - - @Observes(value = { stop, failure, shutdown }, kind = resilient) - synchronized void cancelPeriodicUpdates(ContainerLifecycle ignore) { - - if (periodicUpdates != null){ - log.trace("stopping periodic updates of container profile"); - - try { - periodicUpdates.cancel(true); - periodicUpdates=null; - } - catch(Exception e) { - log.warn("could not stop periodic updates of container profile",e); - } - } - } - - }); - - } - - @Override - public String toString() { - return profile_management; - } -} diff --git a/src/main/java/org/gcube/smartgears/handlers/container/lifecycle/ProfilePublisherImpl.java b/src/main/java/org/gcube/smartgears/handlers/container/lifecycle/ProfilePublisherImpl.java deleted file mode 100644 index f40a4a5..0000000 --- a/src/main/java/org/gcube/smartgears/handlers/container/lifecycle/ProfilePublisherImpl.java +++ /dev/null @@ -1,241 +0,0 @@ -package org.gcube.smartgears.handlers.container.lifecycle; - -import static org.gcube.smartgears.utils.Utils.notEmpty; -import static org.gcube.smartgears.utils.Utils.rethrowUnchecked; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; - -import org.gcube.common.authorization.client.proxy.AuthorizationProxy; -import org.gcube.common.authorization.library.provider.SecurityTokenProvider; -import org.gcube.common.resources.gcore.HostingNode; -import org.gcube.informationsystem.publisher.ScopedPublisher; -import org.gcube.smartgears.configuration.Mode; -import org.gcube.smartgears.context.container.ContainerContext; -import org.gcube.smartgears.handlers.ProfileEvents; -import org.gcube.smartgears.handlers.ProfilePublisher; -import org.gcube.smartgears.provider.ProviderFactory; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Publishes the resource profile of the container. - *

- * Distinguishes publication in new scopes ({@link #addTo(List)} from publication updates in existing scopes ({@link #update(List)}. - * - * @author Fabio Simeoni - * - */ -public class ProfilePublisherImpl implements ProfilePublisher { - - private static final Logger log = LoggerFactory.getLogger(ProfilePublisherImpl.class); - - //the underlying IS publisher - private final ScopedPublisher publisher; - //private final AuthorizationProvider authorization; - private final ContainerContext context; - - private AuthorizationProxy authProxy ; - - /** - * Creates an instance for the container. - * @param context the context of the application - */ - public ProfilePublisherImpl(ContainerContext context) { - this.context = context; - this.publisher=ProviderFactory.provider().publisherFor(context); - this.authProxy = ProviderFactory.provider().authorizationProxy(); - } - - /** - * Adds the current resource profile of the application in one or more - * scopes. The scopes are retrieved from tokens - * @param tokens the tokens - */ - public void addTo(Collection tokens) { - - notEmpty("tokens",tokens); - - log.info("publishing container with tokens {}", tokens); - - HostingNode profile = context.profile(HostingNode.class); - - /* TODO: reintroduce it when scope will be removed - //TODO: remove when move to new IS - Collection retainedContexts = new ArrayList(context.configuration().allowedContexts()); - retainedContexts.removeAll(profile.scopes().asCollection()); - profile.scopes().asCollection().addAll(retainedContexts); - - log.trace("profile scopes on create are {} ",profile.scopes().asCollection()); - - String previousToken = SecurityTokenProvider.instance.get(); - - try { - for (String token: tokens){ - log.info("creating profile with token {}", token); - SecurityTokenProvider.instance.set(token); - profile = publisher.create(profile); - SecurityTokenProvider.instance.reset(); - } - - update(); - - } catch (Exception e) { - log.warn("error adding scopes",e); - rethrowUnchecked(e); - - } finally{ - SecurityTokenProvider.instance.set(previousToken); - }*/ - - ClassLoader contextCL = Thread.currentThread().getContextClassLoader(); - log.debug("using context {}",contextCL.getClass().getSimpleName()); - String previousToken = SecurityTokenProvider.instance.get(); - try{//This classloader set is needed for the jaxb context - if (previousToken==null) - SecurityTokenProvider.instance.set((String)tokens.toArray()[0]); - if (context.configuration().mode()!=Mode.root) - Thread.currentThread().setContextClassLoader(ProfilePublisherImpl.class.getClassLoader()); - profile = publisher.create(profile, resolveScopesFromTokens(tokens)); - } catch (Exception e) { - rethrowUnchecked(e); - } finally { - SecurityTokenProvider.instance.set(previousToken); - if (context.configuration().mode()!=Mode.root) - Thread.currentThread().setContextClassLoader(contextCL); - } - - sharePublished(profile); - - } - - /** - * Adds the current resource profile of the application in one or more scopes. - */ - public void addToAll() { - addTo(context.configuration().startTokens()); - } - - /** - * Updates the current resource profile of the application in its current scopes. - */ - public void update() { - - HostingNode profile = context.profile(HostingNode.class); - /* TODO: reintroduce it when scope will be removed - Collection tokens = context.configuration().startTokens(); - - log.info("updating container with tokens {}", tokens); - - String previousToken = SecurityTokenProvider.instance.get(); - - try { - for (String token: tokens){ - SecurityTokenProvider.instance.set(token); - profile = publisher.update(profile); - SecurityTokenProvider.instance.reset(); - } - sharePublished(profile); - - } - catch (Exception e) { - log.warn("error updating container",e); - rethrowUnchecked(e); - - } finally{ - SecurityTokenProvider.instance.set(previousToken); - }*/ - - - log.debug("[update] resource scopes are : {} ",profile.scopes().asCollection()); - - ClassLoader contextCL = Thread.currentThread().getContextClassLoader(); - log.debug("using context {}",contextCL.getClass().getSimpleName()); - String previousToken = SecurityTokenProvider.instance.get(); - try{//This classloader set is needed for the jaxb context - if (previousToken==null) - SecurityTokenProvider.instance.set((String)context.configuration().startTokens().toArray()[0]); - - if (context.configuration().mode()!=Mode.root) - Thread.currentThread().setContextClassLoader(ProfilePublisherImpl.class.getClassLoader()); - profile = publisher.update(profile); - } catch (Exception e) { - rethrowUnchecked(e); - } finally { - SecurityTokenProvider.instance.set(previousToken); - if (context.configuration().mode()!=Mode.root) - Thread.currentThread().setContextClassLoader(contextCL); - } - - sharePublished(profile); - } - - /** - * Removes the container from one or more scopes. - * @param tokens the tokens - */ - public void removeFrom(Collection tokens) { - - HostingNode profile = context.profile(HostingNode.class); - - log.info("removing container with tokens {}", tokens); - - /* TODO: reintroduce it when scope will be removed - String previousToken = SecurityTokenProvider.instance.get(); - - try { - - for (String token: tokens){ - SecurityTokenProvider.instance.set(token); - profile = publisher.remove(profile); - SecurityTokenProvider.instance.reset(); - } - - update(); - - } - catch (Exception e) { - log.warn("error removing scopes",e); - rethrowUnchecked(e); - - } finally{ - SecurityTokenProvider.instance.set(previousToken); - } */ - - ClassLoader contextCL = Thread.currentThread().getContextClassLoader(); - log.debug("using context {}",contextCL.getClass().getSimpleName()); - String previousToken = SecurityTokenProvider.instance.get(); - try{//This classloader set is needed for the jaxb context - if (previousToken==null) - SecurityTokenProvider.instance.set((String)tokens.toArray()[0]); - if (context.configuration().mode()!=Mode.root) - Thread.currentThread().setContextClassLoader(ProfilePublisherImpl.class.getClassLoader()); - profile = publisher.remove(profile, resolveScopesFromTokens(tokens)); - } catch (Exception e) { - rethrowUnchecked(e); - } finally { - SecurityTokenProvider.instance.set(previousToken); - if (context.configuration().mode()!=Mode.root) - Thread.currentThread().setContextClassLoader(contextCL); - } - - log.debug("after remove container profile contains scopes {}",profile.scopes().asCollection()); - sharePublished(profile); - } - - private void sharePublished(HostingNode profile) { - context.events().fire(profile,ProfileEvents.published); - } - - private List resolveScopesFromTokens(Collection tokens){ - List scopes = new ArrayList(tokens.size()); - for (String token: tokens) - try{ - scopes.add(this.authProxy.get(token).getContext()); - }catch (Exception e) { - log.warn("error retrieving token {} , it should never happen",token); - } - return scopes; - } -} diff --git a/src/main/java/org/gcube/smartgears/health/HealthManager.java b/src/main/java/org/gcube/smartgears/health/HealthManager.java new file mode 100644 index 0000000..2fe5e40 --- /dev/null +++ b/src/main/java/org/gcube/smartgears/health/HealthManager.java @@ -0,0 +1,19 @@ +package org.gcube.smartgears.health; + +import java.util.LinkedList; +import java.util.List; + +import org.gcube.common.health.api.HealthCheck; + +public class HealthManager { + + private List checks = new LinkedList<>(); + + public void register(HealthCheck check){ + checks.add(check); + } + + public List getChecks() { + return checks; + } +} diff --git a/src/main/java/org/gcube/smartgears/health/HealthResponse.java b/src/main/java/org/gcube/smartgears/health/HealthResponse.java new file mode 100644 index 0000000..c1f9dbd --- /dev/null +++ b/src/main/java/org/gcube/smartgears/health/HealthResponse.java @@ -0,0 +1,35 @@ +package org.gcube.smartgears.health; + +import java.util.List; + +import org.gcube.com.fasterxml.jackson.annotation.JsonInclude; +import org.gcube.com.fasterxml.jackson.annotation.JsonInclude.Include; +import org.gcube.common.health.api.Status; +import org.gcube.common.health.api.response.HealthCheckResponse; +import org.gcube.common.validator.annotations.NotNull; + +@JsonInclude(Include.NON_NULL) +public class HealthResponse { + + @NotNull + private Status status; + + private List checks; + + + + public HealthResponse(Status status, List checks) { + super(); + this.status = status; + this.checks = checks; + } + + public Status getStatus() { + return status; + } + + public List getChecks() { + return checks; + } + +} diff --git a/src/main/java/org/gcube/smartgears/health/HealthTask.java b/src/main/java/org/gcube/smartgears/health/HealthTask.java new file mode 100644 index 0000000..ef755d6 --- /dev/null +++ b/src/main/java/org/gcube/smartgears/health/HealthTask.java @@ -0,0 +1,49 @@ +package org.gcube.smartgears.health; + +import java.util.List; +import java.util.TimerTask; +import java.util.stream.Collectors; + +import org.gcube.common.health.api.HealthCheck; +import org.gcube.common.health.api.Status; +import org.gcube.common.health.api.response.HealthCheckResponse; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class HealthTask extends TimerTask{ + + private static final Logger log = LoggerFactory.getLogger(HealthTask.class); + + private HealthResponse response; + + private HealthManager healthManager; + + public HealthTask(HealthManager healthManager) { + this.healthManager = healthManager; + } + + @Override + public void run() { + + List checks = healthManager.getChecks(); + + List responses = checks.stream().map(c -> this.wrap(c)).collect(Collectors.toList()); + Status totalStatus = responses.stream().anyMatch(r -> r.getStatus().equals(Status.DOWN)) ? Status.DOWN : Status.UP; + + this.response = new HealthResponse(totalStatus, responses); + log.debug("health task executed with total status {}",totalStatus); + } + + public HealthResponse getResponse() { + return response; + } + + private HealthCheckResponse wrap(HealthCheck check){ + try { + return check.check(); + }catch (Throwable t) { + return HealthCheckResponse.builder(check.getName()).down().withMessage(t.getMessage()).build(); + } + + } +} diff --git a/src/main/java/org/gcube/smartgears/health/KeyCloakHealthCheck.java b/src/main/java/org/gcube/smartgears/health/KeyCloakHealthCheck.java new file mode 100644 index 0000000..fd087bf --- /dev/null +++ b/src/main/java/org/gcube/smartgears/health/KeyCloakHealthCheck.java @@ -0,0 +1,31 @@ +package org.gcube.smartgears.health; + +import java.util.Set; + +import org.gcube.common.health.api.HealthCheck; +import org.gcube.common.health.api.ReadinessChecker; +import org.gcube.common.health.api.response.HealthCheckResponse; +import org.gcube.smartgears.provider.ProviderFactory; + +@ReadinessChecker +public class KeyCloakHealthCheck implements HealthCheck{ + + private static final String CHECK_NAME = "authorization-check" ; + + public String getName(){ + return CHECK_NAME; + } + + @Override + public HealthCheckResponse check() { + try { + Set contexts = ProviderFactory.provider().containerContext().authorizationProvider().getContexts(); + if (contexts.isEmpty()) + return HealthCheckResponse.builder(CHECK_NAME).down().withMessage("no contexts are defined for the client id provided").build(); + return HealthCheckResponse.builder(CHECK_NAME).up().build(); + }catch (Exception e) { + return HealthCheckResponse.builder(CHECK_NAME).down().withMessage(e.getMessage()).build(); + } + } + +} diff --git a/src/main/java/org/gcube/smartgears/managers/ApplicationManager.java b/src/main/java/org/gcube/smartgears/managers/ApplicationManager.java index 7f3e735..3232aa5 100644 --- a/src/main/java/org/gcube/smartgears/managers/ApplicationManager.java +++ b/src/main/java/org/gcube/smartgears/managers/ApplicationManager.java @@ -15,7 +15,6 @@ import java.io.ObjectOutputStream; import java.util.Collection; import java.util.List; import java.util.Map.Entry; -import java.util.stream.Collectors; import javax.servlet.FilterRegistration; import javax.servlet.ServletContext; @@ -23,25 +22,18 @@ import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener; import javax.servlet.ServletRegistration; -import org.gcube.common.authorization.client.proxy.AuthorizationProxy; -import org.gcube.common.authorization.library.provider.SecurityTokenProvider; import org.gcube.common.events.Observes; -import org.gcube.smartgears.Constants; -import org.gcube.smartgears.configuration.Mode; -import org.gcube.smartgears.configuration.application.ApplicationExtensions; import org.gcube.smartgears.configuration.application.ApplicationHandlers; import org.gcube.smartgears.context.application.ApplicationContext; import org.gcube.smartgears.context.container.ContainerContext; import org.gcube.smartgears.extensions.ApplicationExtension; import org.gcube.smartgears.extensions.RequestExceptionBarrier; -import org.gcube.smartgears.handlers.ProfileEvents; import org.gcube.smartgears.handlers.application.ApplicationLifecycleEvent; import org.gcube.smartgears.handlers.application.ApplicationLifecycleHandler; import org.gcube.smartgears.handlers.application.ApplicationPipeline; import org.gcube.smartgears.handlers.application.RequestHandler; import org.gcube.smartgears.lifecycle.application.ApplicationLifecycle; import org.gcube.smartgears.lifecycle.container.ContainerLifecycle; -import org.gcube.smartgears.utils.Utils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -59,6 +51,8 @@ public class ApplicationManager { private ApplicationContext context; + private List extensions; + /** * Starts application management. * @@ -74,19 +68,9 @@ public class ApplicationManager { for (Entry servlet : application.getServletRegistrations().entrySet()) log.trace("servlet {} : {} {} ", application.getServletContextName(),servlet.getKey(), servlet.getValue().getMappings()); - + context.configuration().validate(); - /* if (context.configuration().secure() && - container.configuration().securePort()==null) - throw new IllegalStateException( - String.format("Application %s cannot be managed because is declared as secure without a secure connector port declared in the container", context.application().getContextPath())); - */ - - if (context.container().configuration().mode()!=Mode.offline) { - context.configuration().startTokens(generateTokensForApplication(container).stream().collect(Collectors.toSet())); - context.configuration().validate(); - } saveApplicationState(); // make context available to application in case it is gcube-aware @@ -96,13 +80,12 @@ public class ApplicationManager { registerObservers(); ApplicationHandlers handlers = provider().handlersFor(context); - handlers.validate(); - - - ApplicationExtensions extensions = provider().extensionsFor(context); + /* + extensions = provider().extensionsFor(context); extensions.validate(); - + */ + List lifecycleHandlers = handlers.lifecycleHandlers(); List requestHandlers = handlers.requestHandlers(); @@ -111,11 +94,12 @@ public class ApplicationManager { log.trace("managing {} requests with {}", context.name(), requestHandlers); log.trace("extending {} API with {}", context.name(), extensions); + extensions = provider().extensionsFor(context); // order is important here: first add APIs - register(extensions); + registerExtension(extensions); // then intercept them all - register(requestHandlers); + registerHandlers(requestHandlers); // start lifecycle management start(lifecycleHandlers); @@ -143,43 +127,8 @@ public class ApplicationManager { } - private List generateTokensForApplication(ContainerContext container){ - log.info("generating token for app {}",context.configuration().name()); - - SecurityTokenProvider.instance.set(container.configuration().startTokens().get(0)); - try { - AuthorizationProxy authProxy = provider().authorizationProxy(); - try { - return authProxy.generateServiceToken(Utils.getServiceInfo(context), container.configuration().startTokens()); - }catch (Exception e) { - log.error("error generating service token",e); - throw new RuntimeException(e); - } - } catch (Exception e) { - throw new RuntimeException("error contacting authorization service",e); - } finally{ - SecurityTokenProvider.instance.reset(); - } - - - } - - private String generateApplicationToken(String containerToken, AuthorizationProxy authProxy){ - SecurityTokenProvider.instance.set(containerToken); - try { - log.info("generating token for app {} with container token {} ",context.configuration().name(), containerToken); - return authProxy.generateServiceToken(Utils.getServiceInfo(context)); - } catch (Exception e) { - throw new RuntimeException("error contacting authorization service",e); - } finally{ - SecurityTokenProvider.instance.reset(); - } - - } - - private void saveApplicationState() { - File file = context.configuration().persistence().file(profile_file_path); + File file = context.persistence().file(profile_file_path); try(ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(file))){ oos.writeObject(context.id()); }catch (Exception e) { @@ -205,7 +154,10 @@ public class ApplicationManager { context.lifecycle().tryMoveTo(stopped); context.events().fire(context, ApplicationLifecycle.stop); - + + if (extensions != null) + unregister(extensions); + stopLifecycleHandlers(); log.info("stopping application events for {}", context.name()); @@ -219,7 +171,7 @@ public class ApplicationManager { } - private void register(List rqHandlers) { + private void registerHandlers(List rqHandlers) { ServletContext app = context.application(); @@ -246,11 +198,11 @@ public class ApplicationManager { } } - private void register(ApplicationExtensions extensions) { + private void registerExtension(List extensions) { ServletContext application = context.application(); - for (ApplicationExtension extension : extensions.extensions()) + for (ApplicationExtension extension : extensions) try { @@ -282,6 +234,14 @@ public class ApplicationManager { } } + + private void unregister(List extensions) { + + for (ApplicationExtension extension : extensions) + extension.stop(); + + } + private void start(List handlers) { @@ -320,28 +280,6 @@ public class ApplicationManager { log.warn("cannot stop {} after container has stopped", context.name()); } - @Observes(value = ContextEvents.ADD_TOKEN_TO_APPLICATION, kind = critical) - void onAddToken(String containerToken) { - log.trace("event add received with token {} ",containerToken); - String appToken = generateApplicationToken(containerToken, provider().authorizationProxy()); - context.configuration().startTokens().add(appToken); - log.trace("app token created : {} ", appToken); - context.events().fire(appToken, ProfileEvents.addToContext); - context.events().fire(appToken, Constants.token_registered); - saveApplicationState(); - } - - @Observes(value = ContextEvents.REMOVE_TOKEN_FROM_APPLICATION, kind = critical) - void onRemoveToken(String containerToken) { - log.trace("event remove received with token {} ",containerToken); - String appToken = generateApplicationToken(containerToken, provider().authorizationProxy()); - context.configuration().startTokens().remove(appToken); - log.trace("app token removed : {} ", appToken); - context.events().fire(appToken, ProfileEvents.removeFromContext); - context.events().fire(appToken, Constants.token_removed); - saveApplicationState(); - } - }; context.container().events().subscribe(observer); @@ -352,7 +290,8 @@ public class ApplicationManager { @Override public void contextInitialized(ServletContextEvent sce) { log.info("initilizing context {} ",context.name()); - context.events().fire(context.application().getContextPath(), ApplicationLifecycle.activation); + + context.events().fire(context, ApplicationLifecycle.activation); log.info("webApp {} initialized ",context.name()); } diff --git a/src/main/java/org/gcube/smartgears/managers/ContainerManager.java b/src/main/java/org/gcube/smartgears/managers/ContainerManager.java index 3d7a9d2..8bf1e50 100644 --- a/src/main/java/org/gcube/smartgears/managers/ContainerManager.java +++ b/src/main/java/org/gcube/smartgears/managers/ContainerManager.java @@ -10,19 +10,12 @@ import static org.gcube.smartgears.provider.ProviderFactory.provider; import java.io.File; import java.io.FileOutputStream; import java.io.ObjectOutputStream; -import java.util.HashSet; import java.util.List; import java.util.Set; -import org.gcube.common.authorization.client.exceptions.ObjectNotFound; -import org.gcube.common.authorization.client.proxy.AuthorizationProxy; -import org.gcube.common.authorization.library.AuthorizationEntry; -import org.gcube.common.authorization.library.provider.ClientInfo; -import org.gcube.common.authorization.library.provider.ContainerInfo; import org.gcube.common.events.Observes; import org.gcube.common.events.Observes.Kind; import org.gcube.smartgears.configuration.Mode; -import org.gcube.smartgears.configuration.container.ContainerHandlers; import org.gcube.smartgears.context.application.ApplicationContext; import org.gcube.smartgears.context.container.ContainerContext; import org.gcube.smartgears.handlers.ProfileEvents; @@ -47,8 +40,6 @@ public class ContainerManager { public static ContainerManager instance = new ContainerManager(); - private AuthorizationProxy authProvider = provider().authorizationProxy(); - private ContainerContext context; private ContainerPipeline pipeline; @@ -70,18 +61,15 @@ public class ContainerManager { saveContainerState(); - ContainerHandlers handlers = provider().containerHandlers(); + List handlers = provider().containerHandlers(); - log.trace("managing container lifecycle with {}", handlers.get()); + log.trace("managing container lifecycle with {}", handlers); - startHandlers(handlers.get()); + + startHandlers(handlers); context.lifecycle().moveTo(active); - - log.trace("loading keys for starting token ..."); - //loadKeyForToken(context.configuration().startTokens()); - log.trace("keys loaded for starting token ..."); - + return context; } catch(RuntimeException e) { @@ -98,10 +86,9 @@ public class ContainerManager { private void saveContainerState() { - File file = context.configuration().persistence().file(container_profile_file_path); + File file = context.persistenceWriter().file(container_profile_file_path); try(ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(file))){ oos.writeObject(context.id()); - oos.writeObject(context.configuration().startTokens()); }catch (Exception e) { log.error("error serializing cointainer state"); throw new RuntimeException(e); @@ -112,59 +99,24 @@ public class ContainerManager { private void validateContainer(ContainerContext context) { //List tokensToRemove = new ArrayList(); context.configuration().validate(); - Set foundContexts= new HashSet(); - + Set foundContexts; + try { - List entries = authProvider.get(context.configuration().startTokens()); - - log.info("requesting auth on {} tokens returned {} entries", context.configuration().startTokens().size(),entries.size()); - - for (AuthorizationEntry entry : entries ) { - log.info("the container will be started in context {}",entry.getContext()); - foundContexts.add(entry.getContext()); - } - + foundContexts = context.authorizationProvider().getContexts(); } catch (Exception e) { - log.error("error contacting auth service on container",e); + log.error("error authorizing container",e); + throw new RuntimeException("error authorizing container, moving the container to failed",e); } if (foundContexts.isEmpty()){ - log.error("no valid starting token are specified, moving the container to failed"); - throw new RuntimeException("no valid starting token are specified"); + log.error("no valid contexts found, moving the container to failed"); + throw new RuntimeException("no valid contexts found, moving the container to failed"); } - //context.configuration().startTokens().removeAll(tokensToRemove); - context.configuration().allowedContexts(foundContexts); - } - - private String resolveTokenForAdd(Set alreadyAddedContext, String token){ - try { - AuthorizationEntry entry = authProvider.get(token); - ClientInfo info = entry.getClientInfo(); - log.info("resolved authorization entry for container {}",entry); - if (alreadyAddedContext.contains(entry.getContext())){ - log.warn("the token {} cannot be used, another token with the same context {} found ", entry.getContext()); - } else if(!entry.getContext().startsWith("/"+context.configuration().infrastructure())){ - log.warn("the token {} cannot be used, is not in the infrastructure {} of the container ", token,context.configuration().infrastructure()); - }else if (!(info instanceof ContainerInfo)){ - log.warn("the token {} cannot be used, is not for a container token ", token); - } else if (!((ContainerInfo)info).getHost().equals(context.configuration().hostname()) - || context.configuration().port()!=((ContainerInfo)info).getPort()){ - log.warn("the token {} cannot be used, the client id {} resolved with the token is not the same of the one specified in this container ", token, info.getId()); - } else - return entry.getContext(); - }catch(ObjectNotFound onf){ - log.error("token {} not valid", token); - } catch (Exception e) { - log.error("error contacting authorization for token {}",token,e); - } - return null; } public void manage(ApplicationContext app) { - app.events().subscribe(this); - } @Observes(value={ApplicationLifecycle.failure,ApplicationLifecycle.stop},kind=Kind.critical) @@ -172,40 +124,16 @@ public class ContainerManager { context.lifecycle().tryMoveTo(ContainerState.partActive); } - @Observes(value=ContextEvents.ADD_TOKEN_TO_CONTAINER,kind=Kind.critical) - void addToken(String token) { - log.trace("adding token {} to container", token); - String newContext; - if ((newContext = resolveTokenForAdd(context.configuration().allowedContexts(), token))!=null) { - context.configuration().startTokens().add(token); - context.configuration().allowedContexts().add(newContext); - saveContainerState(); - //loadKeyForToken(Arrays.asList(token)); - context.events().fire(token, ContextEvents.ADD_TOKEN_TO_APPLICATION); - context.events().fire(token, ProfileEvents.addToContext); - log.trace("token added and event fired"); - } else log.warn("trying to add an invalid token"); + @Observes(value=ContextEvents.ADD_CONTEXT_TO_CONTAINER,kind=Kind.critical) + void addContext(String scope) { + log.info("adding context {} event send", context); + context.events().fire(scope, ProfileEvents.addToContext); } - @Observes(value=ContextEvents.REMOVE_TOKEN_FROM_CONTAINER,kind=Kind.critical) - void removeToken(String token) { - log.trace("removing token {} from container", token); - AuthorizationEntry entry; - try { - entry = authProvider.get(token); - } catch (Exception e) { - log.error("error resolving token to remove"); - return; - } - - if (context.configuration().startTokens().contains(token)) { - context.configuration().startTokens().remove(token); - context.configuration().allowedContexts().remove(entry.getContext()); - saveContainerState(); - context.events().fire(token, ContextEvents.REMOVE_TOKEN_FROM_APPLICATION); - context.events().fire(token, ProfileEvents.removeFromContext); - log.trace("token removed and event fired"); - } else log.warn("cannot remove token, it is not present in the container"); + @Observes(value=ContextEvents.REMOVE_CONTEXT_FROM_CONTAINER,kind=Kind.critical) + void removeContext(String scope) { + log.info("removing context {} event send", context); + context.events().fire(scope, ProfileEvents.removeFromContext); } /** diff --git a/src/main/java/org/gcube/smartgears/managers/ContextEvents.java b/src/main/java/org/gcube/smartgears/managers/ContextEvents.java index 8b771c2..224093b 100644 --- a/src/main/java/org/gcube/smartgears/managers/ContextEvents.java +++ b/src/main/java/org/gcube/smartgears/managers/ContextEvents.java @@ -2,12 +2,9 @@ package org.gcube.smartgears.managers; public class ContextEvents { - public static final String ADD_TOKEN_TO_CONTAINER ="AddTokenToContainer"; + public static final String ADD_CONTEXT_TO_CONTAINER ="AddContextToContainer"; - public static final String ADD_TOKEN_TO_APPLICATION ="AddTokenToApplication"; + public static final String REMOVE_CONTEXT_FROM_CONTAINER ="RemoveContextFromContainer"; - public static final String REMOVE_TOKEN_FROM_CONTAINER ="RemoveTokenFromContainer"; - - public static final String REMOVE_TOKEN_FROM_APPLICATION ="RemoveTokenFromApplication"; } diff --git a/src/main/java/org/gcube/smartgears/managers/RequestManager.java b/src/main/java/org/gcube/smartgears/managers/RequestManager.java index 11cf66c..cf28d8b 100644 --- a/src/main/java/org/gcube/smartgears/managers/RequestManager.java +++ b/src/main/java/org/gcube/smartgears/managers/RequestManager.java @@ -8,6 +8,7 @@ import java.io.IOException; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.stream.Collectors; import javax.servlet.Filter; import javax.servlet.FilterChain; @@ -19,8 +20,8 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.gcube.common.authorization.library.exception.AuthorizationException; -import org.gcube.smartgears.configuration.application.Exclude; -import org.gcube.smartgears.configuration.application.Include; +import org.gcube.smartgears.configuration.application.GCubeExclude; +import org.gcube.smartgears.configuration.application.GCubeInclude; import org.gcube.smartgears.context.application.ApplicationContext; import org.gcube.smartgears.context.application.DefaultApplicationContext; import org.gcube.smartgears.handlers.application.ApplicationPipeline; @@ -136,27 +137,27 @@ public class RequestManager implements Filter { log.debug("check wich handler should be excluded {}", path); if (!context.configuration().excludes().isEmpty()) { - for (Exclude exclude : context.configuration().excludes()){ + for (GCubeExclude exclude : context.configuration().excludes()){ String excludePath= exclude.getPath(); log.trace("exclude is {}",exclude); - if ( - (WILDCARD).equals(excludePath) || + if ((WILDCARD).equals(excludePath) || (excludePath.endsWith(WILDCARD) && path!=null && path.startsWith(excludePath.substring(0,excludePath.length()-2))) || excludePath.equals(path) || (path.endsWith("/") && excludePath.equals(path.substring(0, path.length()-1))) ){ - //ALL handler are filtered - if (exclude.getHandlers().isEmpty()) return Collections.emptyList(); + //ALL handler are filtered except for unfiltrable + if (exclude.getHandlers().isEmpty()) return handlersToFilter.stream() + .filter(RequestHandler::isUnfiltrable).collect(Collectors.toList()); List filteredHandlers = new ArrayList<>(); - for (RequestHandler rh : handlersToFilter){ - if (!exclude.getHandlers().contains(rh.getName())) + for (RequestHandler rh : handlersToFilter) + if (rh.isUnfiltrable() || !exclude.getHandlers().contains(rh.getName())) filteredHandlers.add(rh); - } + return filteredHandlers; } } } else if (!context.configuration().includes().isEmpty()) { - for (Include include : context.configuration().includes()){ + for (GCubeInclude include : context.configuration().includes()){ String includePath= include.getPath(); log.trace("include is {}",include); if ( @@ -168,10 +169,10 @@ public class RequestManager implements Filter { if (include.getHandlers().isEmpty()) return handlersToFilter; List filteredHandlers = new ArrayList<>(); - for (RequestHandler rh : handlersToFilter){ - if (include.getHandlers().contains(rh.getName())) + for (RequestHandler rh : handlersToFilter) + if (rh.isUnfiltrable() || include.getHandlers().contains(rh.getName())) filteredHandlers.add(rh); - } + return filteredHandlers; } } @@ -213,37 +214,6 @@ public class RequestManager implements Filter { } - // helpers - /* - private boolean shouldExcludeRequest(HttpServletRequest request) { - - String query = request.getQueryString(); - - log.debug("servletPath is {} and pathInfo is {}",request.getServletPath(), request.getPathInfo()); - - if ("wsdl".equals(query) || "wsdl=1".equals(query)) - return true; - - String path = request.getServletPath()==null?"":request.getServletPath(); - - path += request.getPathInfo() ==null?"":request.getPathInfo(); - - - log.debug("check if should exclude call with path {}", path); - - for (Exclude exclude : context.configuration().excludes()){ - if (!exclude.getHandlers().isEmpty()) continue; - String excludePath= exclude.getPath(); - log.trace("exclude is {}",exclude); - if ( - (EXCLUDE_ALL).equals(exclude) || - (excludePath.endsWith(EXCLUDE_ALL) && path!=null && path.startsWith(excludePath.substring(0,excludePath.length()-2))) || - excludePath.equals(path) || (path.endsWith("/") && excludePath.equals(path.substring(0, path.length()-1))) - ) - return true; - } - return false; - }*/ private void handleError(HttpServletRequest request, HttpServletResponse response,Throwable t) throws IOException { diff --git a/src/main/java/org/gcube/smartgears/persistence/DefaultPersistence.java b/src/main/java/org/gcube/smartgears/persistence/DefaultPersistence.java deleted file mode 100644 index 21dbbc3..0000000 --- a/src/main/java/org/gcube/smartgears/persistence/DefaultPersistence.java +++ /dev/null @@ -1,96 +0,0 @@ -package org.gcube.smartgears.persistence; - - -import static org.gcube.smartgears.utils.Utils.*; - -import java.io.File; - -import javax.xml.bind.Unmarshaller; -import javax.xml.bind.annotation.XmlAttribute; -import javax.xml.bind.annotation.XmlRootElement; - -import org.gcube.common.validator.annotations.NotNull; - -@XmlRootElement(name="persistence") -public class DefaultPersistence implements Persistence { - - @XmlAttribute(name="location") @NotNull - private String location; - - public DefaultPersistence() {} - - public DefaultPersistence(String location) { - - notNull("persistence location",location); - - this.location=location; - validate(); - } - - @Override - public String location() { - return location; - } - - @Override - public File writefile(String path) { - - notNull("relative path", path); - - return fileAt(new File(location, path).getAbsolutePath()).toWrite(); - } - - @Override - public File file(String path) { - - notNull("relative path", path); - - return fileAt(new File(location, path).getAbsolutePath()).toRead(); - } - - - //called after JAXB unmarshalling to purge unavailable handlers - void afterUnmarshal(Unmarshaller u, Object parent) { - - validate(); - } - - public void validate() { - - File locationDir = new File(location); - if (!(locationDir.exists() && locationDir.isDirectory() && locationDir.canRead() && locationDir.canWrite())) - throw new IllegalStateException("invalid node configuration: home "+location+" does not exist or is not a directory or cannot be accessed in read/write mode"); - - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((location == null) ? 0 : location.hashCode()); - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - DefaultPersistence other = (DefaultPersistence) obj; - if (location == null) { - if (other.location != null) - return false; - } else if (!location.equals(other.location)) - return false; - return true; - } - - @Override - public String toString() { - return "local persistence in "+location; - } - -} diff --git a/src/main/java/org/gcube/smartgears/persistence/LocalWriter.java b/src/main/java/org/gcube/smartgears/persistence/LocalWriter.java new file mode 100644 index 0000000..08a3327 --- /dev/null +++ b/src/main/java/org/gcube/smartgears/persistence/LocalWriter.java @@ -0,0 +1,68 @@ +package org.gcube.smartgears.persistence; + +import static org.gcube.smartgears.utils.Utils.fileAt; +import static org.gcube.smartgears.utils.Utils.notNull; + +import java.io.File; +import java.nio.file.Files; +import java.nio.file.Paths; + +import org.gcube.smartgears.configuration.ComponentConfiguration; +import org.gcube.smartgears.configuration.ConfiguredWith; + +@ConfiguredWith(LocalWriterConfiguration.class) +public class LocalWriter implements PersistenceWriter { + + private String location; + + @Override + public void configure(ComponentConfiguration configuration) { + this.location = ((LocalWriterConfiguration) configuration).getLocation(); + + } + + + public String getLocation() { + return location; + } + + public void setLocation(String location) { + this.location = location; + } + + + @Override + public File writefile(String path) { + + notNull("relative path", path); + + return fileAt(new File(location, path).getAbsolutePath()).toWrite(); + } + + @Override + public File file(String path) { + + notNull("relative path", path); + + return fileAt(new File(location, path).getAbsolutePath()).toRead(); + } + + + public void validate() { + + File locationDir = new File(location); + if (!(locationDir.exists() && locationDir.isDirectory() && locationDir.canRead() && locationDir.canWrite())) + throw new IllegalStateException("invalid node configuration: home "+location+" does not exist or is not a directory or cannot be accessed in read/write mode"); + + } + + @Override + public long getFreeSpace() { + try { + return Files.getFileStore(Paths.get(location)).getUsableSpace(); + }catch (Exception e) { + return -1; + } + } + +} diff --git a/src/main/java/org/gcube/smartgears/persistence/LocalWriterConfiguration.java b/src/main/java/org/gcube/smartgears/persistence/LocalWriterConfiguration.java new file mode 100644 index 0000000..41d0f14 --- /dev/null +++ b/src/main/java/org/gcube/smartgears/persistence/LocalWriterConfiguration.java @@ -0,0 +1,24 @@ +package org.gcube.smartgears.persistence; + +import org.gcube.common.validator.annotations.NotEmpty; +import org.gcube.common.validator.annotations.NotNull; +import org.gcube.smartgears.configuration.ComponentConfiguration; + +public class LocalWriterConfiguration implements ComponentConfiguration{ + + @NotEmpty @NotNull + private String location; + + protected LocalWriterConfiguration() {} + + public LocalWriterConfiguration(String location) { + super(); + this.location = location; + } + + public String getLocation() { + return location; + } + + +} diff --git a/src/main/java/org/gcube/smartgears/persistence/Persistence.java b/src/main/java/org/gcube/smartgears/persistence/Persistence.java deleted file mode 100644 index 058480e..0000000 --- a/src/main/java/org/gcube/smartgears/persistence/Persistence.java +++ /dev/null @@ -1,13 +0,0 @@ -package org.gcube.smartgears.persistence; - -import java.io.File; - -public interface Persistence { - - String location(); - - File file(String path); - - File writefile(String path); - -} \ No newline at end of file diff --git a/src/main/java/org/gcube/smartgears/persistence/PersistenceWriter.java b/src/main/java/org/gcube/smartgears/persistence/PersistenceWriter.java new file mode 100644 index 0000000..b79e21a --- /dev/null +++ b/src/main/java/org/gcube/smartgears/persistence/PersistenceWriter.java @@ -0,0 +1,17 @@ +package org.gcube.smartgears.persistence; + +import java.io.File; + +import org.gcube.smartgears.configuration.Configurable; + +public interface PersistenceWriter extends Configurable{ + + File file(String path); + + File writefile(String path); + + long getFreeSpace(); + + String getLocation(); + +} \ No newline at end of file diff --git a/src/main/java/org/gcube/smartgears/provider/DefaultProvider.java b/src/main/java/org/gcube/smartgears/provider/DefaultProvider.java index 1466d25..1308cc8 100644 --- a/src/main/java/org/gcube/smartgears/provider/DefaultProvider.java +++ b/src/main/java/org/gcube/smartgears/provider/DefaultProvider.java @@ -1,66 +1,52 @@ package org.gcube.smartgears.provider; -import static org.gcube.common.authorization.client.Constants.authorizationService; 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.container_handlers_file_name; -import static org.gcube.smartgears.Constants.application_handlers_file_name; -import static org.gcube.smartgears.Constants.container_handlers_file_path; -import static org.gcube.smartgears.Constants.container_profile_file_path; -import static org.gcube.smartgears.Constants.default_extensions_file_path; -import static org.gcube.smartgears.Constants.default_handlers_file_path; -import static org.gcube.smartgears.Constants.extensions_file_path; import static org.gcube.smartgears.Constants.ghn_home_env; import static org.gcube.smartgears.Constants.ghn_home_property; -import static org.gcube.smartgears.Constants.handlers_file_path; -import static org.gcube.smartgears.Constants.library_configuration_file_path; -import static org.gcube.smartgears.Constants.profile_file_path; import java.io.File; import java.io.FileInputStream; import java.io.InputStream; -import java.io.ObjectInputStream; -import java.net.URL; -import java.net.URLClassLoader; -import java.util.Arrays; -import java.util.Collection; -import java.util.HashSet; +import java.util.ArrayList; import java.util.List; -import java.util.UUID; +import java.util.Set; +import java.util.stream.Collectors; import javax.servlet.ServletContext; -import org.gcube.common.authorization.client.proxy.AuthorizationProxy; + import org.gcube.common.events.Hub; import org.gcube.common.events.impl.DefaultHub; -import org.gcube.common.scan.ClasspathScanner; -import org.gcube.common.scan.ClasspathScannerFactory; -import org.gcube.common.scan.matchers.NameMatcher; -import org.gcube.common.scan.resources.ClasspathResource; -import org.gcube.informationsystem.publisher.RegistryPublisherFactory; -import org.gcube.informationsystem.publisher.ScopedPublisher; -import org.gcube.smartgears.configuration.Mode; +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.ApplicationExtensions; import org.gcube.smartgears.configuration.application.ApplicationHandlers; -import org.gcube.smartgears.configuration.application.BridgedApplicationConfiguration; import org.gcube.smartgears.configuration.container.ContainerConfiguration; import org.gcube.smartgears.configuration.container.ContainerConfigurationBinder; -import org.gcube.smartgears.configuration.container.ContainerHandlers; -import org.gcube.smartgears.configuration.library.SmartGearsConfiguration; -import org.gcube.smartgears.configuration.library.SmartGearsConfigurationBinder; 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.persistence.DefaultPersistence; +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. * @@ -72,107 +58,56 @@ 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) + // TODO: do the same with applicationContext (with a map) - protected DefaultProvider(){}; + private File configFile = null; + + protected DefaultProvider(File configFile) { + this.configFile = configFile; + } + + List publishers; + + protected DefaultProvider() { + }; - @SuppressWarnings("unchecked") @Override public ContainerContext containerContext() { - if(containerContext==null){ + if (containerContext == null) { ContainerConfiguration configuration = containerConfiguration(); - if (configuration.persistence()==null) { - String location = Utils.home()+"/state"; - File dir = new File(location); - if (!dir.exists()) - dir.mkdirs(); - configuration.persistence(new DefaultPersistence(location)); - - log.trace("setting persistence location for container @ {}",dir.getAbsolutePath()); - } - Hub hub = new DefaultHub(); ContainerLifecycle lifecycle = new ContainerLifecycle(hub); + + AuthorizationProviderFactory authfactory = configuration.authorizationConfiguration() + .getAuthProviderFactory(); + Credentials credentials = configuration.authorizationConfiguration().getCredentials(); - File file = configuration.persistence().file(container_profile_file_path); + AuthorizationProvider authProvider = authfactory.connect(credentials); - String id = null; - List tokens = null; - if (file.exists()){ - log.info("loading persisted state for container"); - try(ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file))){ - id = (String)ois.readObject(); - tokens = (List) ois.readObject(); - }catch(Exception e){ - log.error("error loading persisted state, creating new uuid",e); - } - - } - if (id==null){ - id = UUID.randomUUID().toString(); - log.info("container id created is {}",id); - - } - - if (tokens!=null) - configuration.startTokens(tokens); - - containerContext = new DefaultContainerContext(id, configuration, hub, lifecycle, new Properties()); + containerContext = new DefaultContainerContext(configuration, hub, lifecycle, authProvider, + new Properties()); } return containerContext; } @Override - public ContainerHandlers containerHandlers() { + public List containerHandlers() { try { - InputStream config = getClass().getResourceAsStream(container_handlers_file_path); - - if (config == null) - throw new IllegalStateException("invalid distribution: cannot find " + container_handlers_file_path); - ContainerConfigurationBinder binder = new ContainerConfigurationBinder(); - ContainerHandlers defaultHandlers = binder.bindHandlers(config); - + ClassLoader currentClassLoader = Thread.currentThread().getContextClassLoader(); - if (currentClassLoader.getParent()!=null && !currentClassLoader.getParent().equals(ClassLoader.getSystemClassLoader())){ + if (currentClassLoader.getParent() != null + && !currentClassLoader.getParent().equals(ClassLoader.getSystemClassLoader())) { log.trace("probably i'm in a webapp classloader"); currentClassLoader = currentClassLoader.getParent(); } - - - try{ - if (currentClassLoader instanceof URLClassLoader){ - URL[] urls = ((URLClassLoader) currentClassLoader).getURLs() ; - if (urls!=null && urls.length>0){ - ClasspathScanner scanner = ClasspathScannerFactory.scanner(new HashSet(Arrays.asList(urls))); - Collection resources = scanner.scan(new NameMatcher(container_handlers_file_name)); - - for (URL url: urls) - log.trace("URL: "+ url.toString()); - - if (resources==null || resources.isEmpty()) - log.info("no custom container handlers found in the classpath"); - - for (ClasspathResource res : resources){ - try{ - ContainerHandlers customHandlers= binder.bindHandlers(res.stream()); - defaultHandlers.mergeWith(customHandlers); - log.trace("container hadlers found in {}",res.name()); - }catch(Exception e){ - log.warn("error loading not default container handlers {}",res.name(),e); - } - } - } - } else log.info("this classloader is not instance of {} : ",URLClassLoader.class.getName(), currentClassLoader.getClass().getName()); - }catch(Exception e){ - log.warn("cannot load custom handlers for container from the root classloader",e); - } + List defaultHandlers = binder.bindHandlers(currentClassLoader); return defaultHandlers; @@ -186,63 +121,20 @@ public class DefaultProvider implements Provider { @Override public ApplicationContext contextFor(ContainerContext context, ServletContext application) { - ApplicationConfiguration configuration = null; ApplicationConfiguration embedded = configurationFor(application); - ApplicationConfiguration external = context.configuration().app(application.getContextPath()); - - - - //shouldn't happen: management shouldn't have started at all - if (embedded==null && external==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); - - //no embedded configuration - if (embedded == null) { - - configuration = external ; - - log.info("loaded configuration for application "+configuration.name()+" from "+container_configuraton_file_path); - } - else { - - configuration = embedded; - - if (external == null) - - log.info("loaded configuration for application "+configuration.name()+" from "+configuration_file_path); - - else { - - configuration.merge(external); - - log.info("loaded configuration for application "+configuration.name()+" from "+configuration_file_path+" and "+container_configuraton_file_path); - - } - } - - // TODO we can check scopes here instead of in BridgedApplicationConfiguration constructor - ApplicationConfiguration bridgedConfiguration = new BridgedApplicationConfiguration(context.configuration(), - configuration); + + // 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, configuration.name()); + ApplicationLifecycle lifecycle = new ApplicationLifecycle(hub, embedded.name()); - File file = bridgedConfiguration.persistence().file(profile_file_path); - String id= null; - if (file.exists()){ - log.info("loading persisted state for application {}", application.getContextPath()); - try(ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file))){ - id = (String)ois.readObject(); - }catch(Exception e){ - log.error("error loading persisted state, creating new uuid",e); - } - } - if (id==null) - id = UUID.randomUUID().toString(); - - return new DefaultApplicationContext(id, context, application, bridgedConfiguration, hub, lifecycle, + return new DefaultApplicationContext(context, application, embedded, hub, lifecycle, new Properties()); } @@ -251,140 +143,46 @@ public class DefaultProvider implements Provider { try { - // it's in a library, using - InputStream defaultHandlersStream = getClass().getResourceAsStream(default_handlers_file_path); - - if (defaultHandlersStream == null) - throw new IllegalStateException("invalid distribution: cannot find " + default_handlers_file_path); - ApplicationConfigurationBinder binder = new ApplicationConfigurationBinder(); - ApplicationHandlers defaultHandlers = binder.bindHandlers(defaultHandlersStream); - - //searching for smartegars related application handlers in the common classloader + // searching for smartegars related application handlers in the common + // classloader ClassLoader currentClassLoader = Thread.currentThread().getContextClassLoader(); - if (currentClassLoader.getParent()!=null && !currentClassLoader.getParent().equals(ClassLoader.getSystemClassLoader())){ + if (currentClassLoader.getParent() != null + && !currentClassLoader.getParent().equals(ClassLoader.getSystemClassLoader())) { log.trace("probably i'm in a webapp classloader"); currentClassLoader = currentClassLoader.getParent(); } - - - try{ - if (currentClassLoader instanceof URLClassLoader){ - URL[] urls = ((URLClassLoader) currentClassLoader).getURLs() ; - if (urls!=null && urls.length>0){ - ClasspathScanner scanner = ClasspathScannerFactory.scanner(new HashSet(Arrays.asList(urls))); - Collection resources = scanner.scan(new NameMatcher(application_handlers_file_name)); - if (resources==null || resources.isEmpty()) - log.info("no custom smartgears related application handlers found in the classpath"); - - for (ClasspathResource res : resources){ - try{ - ApplicationHandlers customHandlers= binder.bindHandlers(res.stream()); - defaultHandlers.mergeWith(customHandlers); - log.trace("application hadlers found in {}",res.name()); - }catch(Exception e){ - log.warn("error loading smartgears related application handlers {}",res.name(),e); - } - } - } - } - }catch(Exception e){ - log.warn("cannot load smartgears related handlers for application from the root classloader",e); - } - - InputStream appSpecificHandlersStream = context.application().getResourceAsStream(handlers_file_path); - - if (appSpecificHandlersStream !=null ){ - defaultHandlers.mergeWith(binder.bindHandlers(appSpecificHandlersStream)); - log.trace("{} uses default lifecycle with app spceific handler as it includes {}", context.name(), handlers_file_path); - } else - log.trace("{} uses the default lifecycle as it does not include {}", context.name(), handlers_file_path); - - return defaultHandlers; + ApplicationHandlers defaultHandlers = binder.bindHandlers(currentClassLoader); + return defaultHandlers; } catch (RuntimeException e) { - throw new RuntimeException("cannot install handlers for application @ " + context.name()+" (see cause) ", e); + throw new RuntimeException("cannot install handlers for application @ " + context.name() + " (see cause) ", + e); } } - - @Override - public ApplicationExtensions extensionsFor(ApplicationContext context) { - - try { - - InputStream config = context.application().getResourceAsStream(extensions_file_path); - - if (config == null) { - - log.trace("{} uses default extensions as it does not include {}", context.name(), extensions_file_path); - - // it's in a library, using - config = getClass().getResourceAsStream(default_extensions_file_path); - - if (config == null) - throw new IllegalStateException("invalid distribution: cannot find " + default_extensions_file_path); - - } else - log.info("{} uses custom extensions @ {}", context.name(), extensions_file_path); - - ApplicationConfigurationBinder binder = new ApplicationConfigurationBinder(); - - return binder.bindExtensions(config); - - } catch (RuntimeException e) { - - throw new RuntimeException("cannot install extensions for application @ " + context.name()+" (see cause) ", e); - - } - } - - - @Override - public SmartGearsConfiguration smartgearsConfiguration() { - - try { - - InputStream config = getClass().getResourceAsStream(library_configuration_file_path); - - if (config == null) - throw new IllegalStateException("invalid distribution: cannot find " + library_configuration_file_path); - - SmartGearsConfigurationBinder binder = new SmartGearsConfigurationBinder(); - - SmartGearsConfiguration configuration = binder.bind(config); - - configuration.validate(); - - return configuration; - - } catch (RuntimeException e) { - - throw new RuntimeException("cannot read library configuration (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) + if (config == null) return null; ApplicationConfigurationBinder binder = new ApplicationConfigurationBinder(); - return binder.bind(config); + return binder.load(config); } catch (RuntimeException e) { @@ -395,76 +193,101 @@ public class DefaultProvider implements Provider { private ContainerConfiguration containerConfiguration() { - String home = Utils.home(); + if (configFile == null) { - 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"); + String home = Utils.home(); - File homeDir = new File(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"); - 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"); + File homeDir = new File(home); - File config = new File(homeDir,container_configuraton_file_path); + 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"); - if (!(config.exists() && config.canRead())) - throw new IllegalStateException("invalid node configuration: file "+config.getAbsolutePath()+" does not exist or cannot be accessed"); + configFile = new File(homeDir, container_configuraton_file_path); - - log.trace("reading container configuration @ {} ", config.getAbsolutePath()); - - ContainerConfigurationBinder binder = new ContainerConfigurationBinder(); - - FileInputStream stream = null; - try { - - stream = new FileInputStream(config); - - } - catch(Exception e) { - throw new RuntimeException("unexpected exception reading container configuration file see cause)",e); + log.trace("reading container configuration @ {} ", configFile.getAbsolutePath()); } - ContainerConfiguration configuration = binder.bind(stream); + if (!(configFile.exists() && configFile.canRead())) + throw new IllegalStateException("invalid node configuration: file " + configFile.getAbsolutePath() + + " does not exist or cannot be accessed"); - try { - stream.close(); - } - catch(Exception e) { - log.warn("could not close stream when reading container configuration @ "+config.getAbsolutePath()+" (see cause)",e); + 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 RegistryPublisher publisherFor(ContainerContext context) { - return context.configuration().mode()==Mode.online? - RegistryPublisherFactory.create(): new OfflinePublisher(); - } - - @Override - public RegistryPublisher publisherFor(ApplicationContext context) { - return context.configuration().mode()==Mode.online? - RegistryPublisherFactory.create(): new OfflinePublisher(); - }*/ - - @Override - public ScopedPublisher publisherFor(ContainerContext context) { - return context.configuration().mode()==Mode.online? RegistryPublisherFactory.scopedPublisher() - : new OfflinePublisher(); - } - - @Override - public ScopedPublisher publisherFor(ApplicationContext context) { - return context.configuration().mode()==Mode.online? RegistryPublisherFactory.scopedPublisher() - : new OfflinePublisher(); - } - - @Override - public AuthorizationProxy authorizationProxy() { - return authorizationService(); - } + * @Override public AuthorizationProvider authorizationProvider() { return + * containerContext.authorizationProvider(); } + */ + + } diff --git a/src/main/java/org/gcube/smartgears/provider/OfflinePublisher.java b/src/main/java/org/gcube/smartgears/provider/OfflinePublisher.java deleted file mode 100644 index 4f1cc1d..0000000 --- a/src/main/java/org/gcube/smartgears/provider/OfflinePublisher.java +++ /dev/null @@ -1,56 +0,0 @@ -package org.gcube.smartgears.provider; - -import java.lang.reflect.Method; -import java.util.List; - -import org.gcube.common.resources.gcore.Resource; -import org.gcube.informationsystem.publisher.ScopedPublisher; -import org.gcube.informationsystem.publisher.exception.RegistryNotFoundException; -import org.gcube.smartgears.configuration.Mode; - -/** - * An implementation of {@link ScopedPublisher} that simulates remote publication. - *

- * Used for applications and or containers that operate in {@link Mode#offline}. - * - * @author Fabio Simeoni - * - */ -public class OfflinePublisher implements ScopedPublisher { - - @Override - public T update(T resource){ - // do nothing - return resource; - } - - @Override - public T create(T resource, List scopes) - throws RegistryNotFoundException { - // fragile! bypass restrictions reflectively and set new scope - for (String scope : scopes) - try { - Method m = resource.getClass().getSuperclass().getDeclaredMethod("addScope", String.class); - m.setAccessible(true); - m.invoke(resource, scope); - } catch (Exception e) { - throw new RuntimeException("could not simulate publication in scope " + scope, e); - } - return resource; - } - - @Override - public T remove(T resource, List scopes) - throws RegistryNotFoundException { - for (String scope : scopes) - try { - Method m = resource.getClass().getSuperclass().getDeclaredMethod("removeScope", String.class); - m.setAccessible(true); - m.invoke(resource, scope); - } catch (Exception e) { - throw new RuntimeException("could not simulate publication remove from scope " + scope, e); - } - return resource; - } - -} diff --git a/src/main/java/org/gcube/smartgears/provider/Provider.java b/src/main/java/org/gcube/smartgears/provider/Provider.java index 13f538d..80ae602 100644 --- a/src/main/java/org/gcube/smartgears/provider/Provider.java +++ b/src/main/java/org/gcube/smartgears/provider/Provider.java @@ -1,15 +1,16 @@ package org.gcube.smartgears.provider; +import java.util.List; + import javax.servlet.ServletContext; -import org.gcube.common.authorization.client.proxy.AuthorizationProxy; -import org.gcube.informationsystem.publisher.ScopedPublisher; -import org.gcube.smartgears.configuration.application.ApplicationExtensions; +import org.gcube.smartgears.configuration.SmartgearsConfiguration; import org.gcube.smartgears.configuration.application.ApplicationHandlers; -import org.gcube.smartgears.configuration.container.ContainerHandlers; -import org.gcube.smartgears.configuration.library.SmartGearsConfiguration; import org.gcube.smartgears.context.application.ApplicationContext; import org.gcube.smartgears.context.container.ContainerContext; +import org.gcube.smartgears.extensions.ApplicationExtension; +import org.gcube.smartgears.handlers.container.ContainerHandler; +import org.gcube.smartgears.publishing.Publisher; /** * Provides dependencies for container and application management. @@ -24,8 +25,9 @@ public interface Provider { /** * Returns the runtime properties. * @return the properties. - */ + SmartGearsConfiguration smartgearsConfiguration(); + */ /** * Assembles and returns the context of the container. @@ -37,15 +39,14 @@ public interface Provider { * Returns the handlers associated with the container. * @return the handlers */ - ContainerHandlers containerHandlers(); + List containerHandlers(); /** * Returns an implementation of the IS publisher for the container - * @param application the context of the container * @return the publisher implementation */ - ScopedPublisher publisherFor(ContainerContext application); + List publishers(); //application-level dependencies @@ -65,25 +66,8 @@ public interface Provider { */ ApplicationHandlers handlersFor(ApplicationContext application); - /** - * Returns the API extensions associated with a given application. - * @param application the context of the application - * @return the extensions - */ - ApplicationExtensions extensionsFor(ApplicationContext application); + List extensionsFor(ApplicationContext application); - /** - * Returns an implementation of the IS publisher for a given application - * @param application the context of the application - * @return the publisher implementation - */ - ScopedPublisher publisherFor(ApplicationContext application); - - /** - * Returns an implementation of the IS publisher for a given application - * @param application the context of the application - * @return the publisher implementation - */ - AuthorizationProxy authorizationProxy(); + SmartgearsConfiguration smartgearsConfiguration(); } diff --git a/src/main/java/org/gcube/smartgears/publishing/Publisher.java b/src/main/java/org/gcube/smartgears/publishing/Publisher.java new file mode 100644 index 0000000..28a223c --- /dev/null +++ b/src/main/java/org/gcube/smartgears/publishing/Publisher.java @@ -0,0 +1,63 @@ +package org.gcube.smartgears.publishing; + +import java.util.Set; + +import org.gcube.smartgears.context.application.ApplicationContext; +import org.gcube.smartgears.context.container.ContainerContext; + +public interface Publisher { + + /** + * creates the container resource in the context + * + * @param container + * @param contexts the new contexts where the resource must be created + * @return + */ + boolean create(ContainerContext container, Set contexts); + + /** + * creates the application resource in the contexts + * + * @param application + * @param contexts the new contexts where the resource must be created + * @return + */ + boolean create(ApplicationContext application, Set contexts); + + + /** + * updates the application resource + * + * @param application + * @return + */ + boolean update(ApplicationContext application); + + /** + * updates the container resource + * + * @param container + * @return + */ + boolean update(ContainerContext container); + + + /** + * removes the application resource from the contexts + * + * @param application + * @param contexts the contexts from where the resource must be removed + * @return + */ + boolean remove(ApplicationContext application, Set contexts); + + + /** + * removes the container resource from the contexts + * @param application + * @param contexts the contexts from where the resource must be removed + * @return + */ + boolean remove(ContainerContext application, Set contexts); +} diff --git a/src/main/java/org/gcube/smartgears/publishing/SmartgearsProfilePublisher.java b/src/main/java/org/gcube/smartgears/publishing/SmartgearsProfilePublisher.java new file mode 100644 index 0000000..5bd91f5 --- /dev/null +++ b/src/main/java/org/gcube/smartgears/publishing/SmartgearsProfilePublisher.java @@ -0,0 +1,5 @@ +package org.gcube.smartgears.publishing; + +public @interface SmartgearsProfilePublisher { + +} diff --git a/src/main/java/org/gcube/smartgears/security/AuthorizationProvider.java b/src/main/java/org/gcube/smartgears/security/AuthorizationProvider.java new file mode 100644 index 0000000..d18e436 --- /dev/null +++ b/src/main/java/org/gcube/smartgears/security/AuthorizationProvider.java @@ -0,0 +1,15 @@ +package org.gcube.smartgears.security; + +import java.util.Set; + +import org.gcube.common.security.credentials.Credentials; +import org.gcube.common.security.secrets.Secret; + +public interface AuthorizationProvider { + + Set getContexts(); + + Secret getSecretForContext(String context); + + Credentials getCredentials(); +} diff --git a/src/main/java/org/gcube/smartgears/security/AuthorizationProviderFactory.java b/src/main/java/org/gcube/smartgears/security/AuthorizationProviderFactory.java new file mode 100644 index 0000000..63d9eda --- /dev/null +++ b/src/main/java/org/gcube/smartgears/security/AuthorizationProviderFactory.java @@ -0,0 +1,9 @@ +package org.gcube.smartgears.security; + +import org.gcube.common.security.credentials.Credentials; + +public interface AuthorizationProviderFactory { + + T connect(Credentials credentials); + +} diff --git a/src/main/java/org/gcube/smartgears/security/SimpleCredentials.java b/src/main/java/org/gcube/smartgears/security/SimpleCredentials.java new file mode 100644 index 0000000..58ca17b --- /dev/null +++ b/src/main/java/org/gcube/smartgears/security/SimpleCredentials.java @@ -0,0 +1,68 @@ +package org.gcube.smartgears.security; + +import org.gcube.common.security.credentials.Credentials; +import org.gcube.common.validator.annotations.NotEmpty; +import org.gcube.common.validator.annotations.NotNull; + +public class SimpleCredentials implements Credentials{ + + @NotNull @NotEmpty + String clientID; + + @NotNull @NotEmpty + String secret; + + public String getClientID() { + return clientID; + } + + public void setClientID(String clientID) { + this.clientID = clientID; + } + + public String getSecret() { + return secret; + } + + public void setSecret(String secret) { + this.secret = secret; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((clientID == null) ? 0 : clientID.hashCode()); + result = prime * result + ((secret == null) ? 0 : secret.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + SimpleCredentials other = (SimpleCredentials) obj; + if (clientID == null) { + if (other.clientID != null) + return false; + } else if (!clientID.equals(other.clientID)) + return false; + if (secret == null) { + if (other.secret != null) + return false; + } else if (!secret.equals(other.secret)) + return false; + return true; + } + + @Override + public String toString() { + return "SimpleCredentials [clientID=" + clientID + ", secret=" + secret + "]"; + } + + +} diff --git a/src/main/java/org/gcube/smartgears/security/defaults/DefaultAuthorizationProvider.java b/src/main/java/org/gcube/smartgears/security/defaults/DefaultAuthorizationProvider.java new file mode 100644 index 0000000..7c432ff --- /dev/null +++ b/src/main/java/org/gcube/smartgears/security/defaults/DefaultAuthorizationProvider.java @@ -0,0 +1,76 @@ +package org.gcube.smartgears.security.defaults; + +import java.net.URL; +import java.util.Collections; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import org.gcube.common.keycloak.KeycloakClient; +import org.gcube.common.keycloak.KeycloakClientFactory; +import org.gcube.common.keycloak.model.AccessToken.Access; +import org.gcube.common.keycloak.model.ModelUtils; +import org.gcube.common.keycloak.model.TokenResponse; +import org.gcube.common.security.ContextBean; +import org.gcube.common.security.secrets.Secret; +import org.gcube.common.security.secrets.UmaTokenSecret; +import org.gcube.smartgears.security.AuthorizationProvider; +import org.gcube.smartgears.security.SimpleCredentials; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class DefaultAuthorizationProvider implements AuthorizationProvider { + + private static Logger LOG = LoggerFactory.getLogger(DefaultAuthorizationProvider.class); + + private KeycloakClient client = KeycloakClientFactory.newInstance(); + + private SimpleCredentials credentials; + + private String endpoint; + + public DefaultAuthorizationProvider(SimpleCredentials credentials, String endpoint) { + this.credentials = credentials; + this.endpoint = endpoint; + } + + @Override + public Set getContexts() { + Set contexts = new HashSet(); + try { + TokenResponse response = client.queryOIDCToken(new URL(this.endpoint), credentials.getClientID(), credentials.getSecret()); + Map resourceAccess = ModelUtils.getAccessTokenFrom(response).getResourceAccess(); + for (String context : resourceAccess.keySet()) { + try { + ContextBean scope = new ContextBean(context.replaceAll("%2F", "/")); + contexts.add(scope.toString()); + LOG.debug("found context {}",context); + }catch (IllegalArgumentException e) { + LOG.warn("invalid context found in token: {}", context); + } + } + } catch (Exception e) { + LOG.error("error getting OIDToken from keycloak",e); + return Collections.emptySet(); + } + return contexts; + } + + + @Override + public Secret getSecretForContext(String context) { + try { + TokenResponse response = client.queryUMAToken(new URL(this.endpoint), credentials.getClientID(), credentials.getSecret(), context, null); + return new UmaTokenSecret(response.getAccessToken()); + + } catch (Exception e) { + LOG.error("error getting OIDToken from keycloak",e); + throw new RuntimeException("error getting access token for context "+context, e); + } + + } + + public SimpleCredentials getCredentials() { + return credentials; + } +} diff --git a/src/main/java/org/gcube/smartgears/security/defaults/DefaultAuthorizationProviderFactory.java b/src/main/java/org/gcube/smartgears/security/defaults/DefaultAuthorizationProviderFactory.java new file mode 100644 index 0000000..e9d6cb3 --- /dev/null +++ b/src/main/java/org/gcube/smartgears/security/defaults/DefaultAuthorizationProviderFactory.java @@ -0,0 +1,36 @@ +package org.gcube.smartgears.security.defaults; + +import org.gcube.common.security.credentials.Credentials; +import org.gcube.common.validator.annotations.NotEmpty; +import org.gcube.smartgears.security.AuthorizationProviderFactory; +import org.gcube.smartgears.security.SimpleCredentials; + +public class DefaultAuthorizationProviderFactory implements AuthorizationProviderFactory{ + + @NotEmpty + private String endpoint; + + @Override + public DefaultAuthorizationProvider connect(Credentials credentials) { + if (!SimpleCredentials.class.isInstance(credentials)) + throw new IllegalArgumentException("invalid credential type passed"); + if (this.endpoint == null || this.endpoint.isEmpty()) + throw new IllegalArgumentException("invalid enpoint passed"); + return new DefaultAuthorizationProvider((SimpleCredentials)credentials, this.endpoint); + } + + @Override + public String toString() { + return "DefaultAuthorizationProviderFactory [endpoint=" + endpoint + "]"; + } + + public String getEndpoint() { + return endpoint; + } + + public void setEndpoint(String endpoint) { + this.endpoint = endpoint; + } + + +} diff --git a/src/main/java/org/gcube/smartgears/utils/GcubeAccountingValve.java b/src/main/java/org/gcube/smartgears/utils/GcubeAccountingValve.java deleted file mode 100644 index 632b74d..0000000 --- a/src/main/java/org/gcube/smartgears/utils/GcubeAccountingValve.java +++ /dev/null @@ -1,85 +0,0 @@ -package org.gcube.smartgears.utils; - -import java.io.IOException; - -import javax.servlet.ServletException; - -import org.apache.catalina.connector.Request; -import org.apache.catalina.connector.Response; -import org.apache.catalina.valves.ValveBase; -import org.gcube.accounting.datamodel.UsageRecord.OperationResult; -import org.gcube.accounting.datamodel.usagerecords.ServiceUsageRecord; -import org.gcube.accounting.persistence.AccountingPersistence; -import org.gcube.accounting.persistence.AccountingPersistenceFactory; -import org.gcube.common.scope.api.ScopeProvider; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class GcubeAccountingValve extends ValveBase { - - private static Logger log = LoggerFactory.getLogger(GcubeAccountingValve.class); - - private String infra; - private String serviceClass; - private String serviceName; - private String hostAndPort; - - public void setInfra(String infra) { - this.infra = infra; - } - - public void setServiceClass(String serviceClass) { - this.serviceClass = serviceClass; - } - - public void setServiceName(String serviceName) { - this.serviceName = serviceName; - } - - public void setHostAndPort(String hostAndPort) { - this.hostAndPort = hostAndPort; - } - - @Override - public void invoke(Request request, Response response) throws IOException, ServletException { - try { - String callerIp = request.getHeader("x-forwarded-for"); - if (callerIp == null) { - callerIp = request.getRemoteAddr(); - } - - boolean success = response.getStatus()<400; - ScopeProvider.instance.set(infra); - AccountingPersistenceFactory.setFallbackLocation("/tmp"); - AccountingPersistence persistence = AccountingPersistenceFactory.getPersistence(); - ServiceUsageRecord serviceUsageRecord = new ServiceUsageRecord(); - try{ - - serviceUsageRecord.setConsumerId("UNKNOWN"); - serviceUsageRecord.setCallerQualifier("UNKNOWN"); - serviceUsageRecord.setScope(infra); - serviceUsageRecord.setServiceClass(serviceClass); - serviceUsageRecord.setServiceName(serviceName); - serviceUsageRecord.setDuration(200l); - serviceUsageRecord.setHost(hostAndPort); - serviceUsageRecord.setCalledMethod(request.getRequestURI()); - serviceUsageRecord.setCallerHost(callerIp); - serviceUsageRecord.setOperationResult(success?OperationResult.SUCCESS:OperationResult.FAILED); - persistence.account(serviceUsageRecord); - log.info("Request: {} {} {} {} ", infra, request.getContextPath(), request.getRequestURI(), success); - }catch(Exception ex){ - log.warn("invalid record passed to accounting ",ex); - }finally { - ScopeProvider.instance.reset(); - } - - }catch (Exception e) { - log.error("error executing valve", e); - } - getNext().invoke(request, response); - } - - - - -} diff --git a/src/main/java/org/gcube/smartgears/utils/GcubeJwt.java b/src/main/java/org/gcube/smartgears/utils/GcubeJwt.java deleted file mode 100644 index 0d3af5d..0000000 --- a/src/main/java/org/gcube/smartgears/utils/GcubeJwt.java +++ /dev/null @@ -1,86 +0,0 @@ -package org.gcube.smartgears.utils; - -import java.io.UnsupportedEncodingException; -import java.net.URLDecoder; -import java.nio.charset.StandardCharsets; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import org.gcube.com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import org.gcube.com.fasterxml.jackson.annotation.JsonProperty; - -@JsonIgnoreProperties(ignoreUnknown = true) -public class GcubeJwt { - - protected final static List MINIMAL_ROLES = Arrays.asList("Member"); - - @JsonProperty("aud") - private String context; - - @JsonProperty("resource_access") - private Map contextAccess = new HashMap<>(); - - @JsonProperty("preferred_username") - private String username; - - @JsonProperty("given_name") - private String firstName; - - @JsonProperty("family_name") - private String lastName; - - @JsonProperty("clientId") - private String clientId; - - @JsonProperty("email") - private String email; - - public List getRoles(){ - return contextAccess.get(this.context) == null ? MINIMAL_ROLES : contextAccess.get(this.context).roles; - } - - public String getContext() { - try { - return URLDecoder.decode(context, StandardCharsets.UTF_8.toString()); - }catch (UnsupportedEncodingException e) { - return context; - } - } - - public String getUsername() { - return username; - } - - public boolean isExternalService() { - return clientId != null; - } - - public String getFirstName() { - return firstName; - } - - public String getLastName() { - return lastName; - } - - public String getEmail() { - return email; - } - - @Override - public String toString() { - return "GcubeJwt [context=" + getContext() + ", roles=" + getRoles() + ", username=" + username - + ", firstName=" + firstName + ", lastName=" + lastName + ", email=" + email + "]"; - } - - public static class Roles { - - @JsonProperty("roles") - List roles = new ArrayList<>(); - - } - -} diff --git a/src/main/java/org/gcube/smartgears/utils/InnerMethodName.java b/src/main/java/org/gcube/smartgears/utils/InnerMethodName.java index 9c81c21..692975d 100644 --- a/src/main/java/org/gcube/smartgears/utils/InnerMethodName.java +++ b/src/main/java/org/gcube/smartgears/utils/InnerMethodName.java @@ -1,6 +1,5 @@ package org.gcube.smartgears.utils; -import org.gcube.common.authorization.library.provider.CalledMethodProvider; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -8,7 +7,7 @@ public class InnerMethodName { public static InnerMethodName instance = new InnerMethodName(); - private static Logger logger = LoggerFactory.getLogger(CalledMethodProvider.class); + private static Logger logger = LoggerFactory.getLogger(InnerMethodName.class); // Thread local variable containing each thread's ID private static final InheritableThreadLocal threadMethod = diff --git a/src/main/java/org/gcube/smartgears/utils/Utils.java b/src/main/java/org/gcube/smartgears/utils/Utils.java index 43caaa2..42c1a4a 100644 --- a/src/main/java/org/gcube/smartgears/utils/Utils.java +++ b/src/main/java/org/gcube/smartgears/utils/Utils.java @@ -214,7 +214,7 @@ public class Utils { public static ServiceInfo getServiceInfo(ApplicationContext application){ String hostedin = String.format("%s_%d", application.container().configuration().hostname(), application.container().configuration().port()); return - new ServiceInfo(new ServiceIdentifier(application.configuration().serviceClass(), application.configuration().name(), hostedin)); + new ServiceInfo(new ServiceIdentifier(application.configuration().group(), application.configuration().name(), hostedin)); } public static Throwable getCause(Throwable e) { diff --git a/src/main/resources/META-INF/container-handlers.xml b/src/main/resources/META-INF/container-handlers.xml deleted file mode 100644 index 9884b0e..0000000 --- a/src/main/resources/META-INF/container-handlers.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/src/main/resources/META-INF/default-extensions.xml b/src/main/resources/META-INF/default-extensions.xml deleted file mode 100644 index 26845b3..0000000 --- a/src/main/resources/META-INF/default-extensions.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/src/main/resources/META-INF/default-handlers.xml b/src/main/resources/META-INF/default-handlers.xml deleted file mode 100644 index 39ecdba..0000000 --- a/src/main/resources/META-INF/default-handlers.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - diff --git a/src/main/resources/META-INF/frontpage.html b/src/main/resources/META-INF/frontpage.html index 2b587fb..70eaf93 100644 --- a/src/main/resources/META-INF/frontpage.html +++ b/src/main/resources/META-INF/frontpage.html @@ -104,7 +104,7 @@

Welcome to ${name},

-

a resource of the ${infra} infrastructure shared in ${vos} VOs.

+

a resource of the ${infra} infrastructure

The resource is ${status}.

diff --git a/src/main/resources/META-INF/services/org.gcube.smartgears.extensions.ApplicationExtension b/src/main/resources/META-INF/services/org.gcube.smartgears.extensions.ApplicationExtension deleted file mode 100644 index 3a14165..0000000 --- a/src/main/resources/META-INF/services/org.gcube.smartgears.extensions.ApplicationExtension +++ /dev/null @@ -1 +0,0 @@ -org.gcube.smartgears.extensions.resource.RemoteResource \ No newline at end of file diff --git a/src/main/resources/META-INF/services/org.gcube.smartgears.handlers.application.ApplicationHandler b/src/main/resources/META-INF/services/org.gcube.smartgears.handlers.application.ApplicationHandler deleted file mode 100644 index 977cf56..0000000 --- a/src/main/resources/META-INF/services/org.gcube.smartgears.handlers.application.ApplicationHandler +++ /dev/null @@ -1,4 +0,0 @@ -org.gcube.smartgears.handlers.application.lifecycle.ProfileManager -org.gcube.smartgears.handlers.application.request.RequestValidator -org.gcube.smartgears.handlers.application.request.RequestAccounting -org.gcube.smartgears.handlers.application.request.RequestContextRetriever \ No newline at end of file diff --git a/src/main/resources/META-INF/services/org.gcube.smartgears.handlers.container.ContainerHandler b/src/main/resources/META-INF/services/org.gcube.smartgears.handlers.container.ContainerHandler deleted file mode 100644 index 5c13143..0000000 --- a/src/main/resources/META-INF/services/org.gcube.smartgears.handlers.container.ContainerHandler +++ /dev/null @@ -1,2 +0,0 @@ -org.gcube.smartgears.handlers.container.lifecycle.ProfileManager -org.gcube.smartgears.handlers.container.lifecycle.AccountingManager \ No newline at end of file diff --git a/src/test/java/app/Request.java b/src/test/java/app/Request.java deleted file mode 100644 index b58b1bf..0000000 --- a/src/test/java/app/Request.java +++ /dev/null @@ -1,179 +0,0 @@ -package app; - -import static com.sun.jersey.api.client.Client.create; -import static java.util.concurrent.TimeUnit.MILLISECONDS; -import static org.gcube.smartgears.Constants.scope_header; -import static org.gcube.smartgears.extensions.HttpExtension.Method.DELETE; -import static org.gcube.smartgears.extensions.HttpExtension.Method.GET; -import static utils.TestUtils.context_root; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map.Entry; -import java.util.concurrent.CountDownLatch; - -import org.gcube.common.authorization.library.provider.AuthorizationProvider; -import org.gcube.common.authorization.library.provider.UserInfo; -import org.gcube.common.authorization.library.utils.Caller; -import org.gcube.smartgears.extensions.HttpExtension.Method; - -import utils.TestUtils; - -import com.sun.jersey.api.client.Client; -import com.sun.jersey.api.client.ClientResponse; -import com.sun.jersey.api.client.UniformInterfaceException; -import com.sun.jersey.api.client.WebResource.Builder; -import com.sun.jersey.api.client.filter.LoggingFilter; -import com.sun.jersey.core.header.OutBoundHeaders; - - -public class Request { - - private String path=""; - private String scope = TestUtils.scope; - - private OutBoundHeaders headers = new OutBoundHeaders(); - private Method method = GET; - private String body = null; - private boolean logged = false; - - public static Request request() { - return new Request(); - } - - private Request() { - - } - - public Request at(String path) { - this.path=path; - return this; - } - - public Request logging() { - logged=true; - return this; - } - - public Request inScope(String scope) { - this.scope=scope; - return this; - } - - public Request with(String body) { - this.body=body; - return this; - } - - public Request with(String name, String value) { - this.headers.add(name, value); - return this; - } - - public Request using(Method method) { - this.method=method; - return this; - } - - public String path() { - return path; - } - - public String body() { - return body; - } - - public Method method() { - return method; - } - - public String scope() { - return scope; - } - - ClientResponse make(final int port) { - - - // we make a scoped call in a separate thread, with which we then synchronize for completion. - // this helps isolate the caller's thread (Main normally) from the app's thread, - // starting with the scope itself. - final CountDownLatch latch = new CountDownLatch(1); - - class Box { - - volatile UniformInterfaceException failure; - volatile ClientResponse response; - - } - - final Box box = new Box(); - - new Thread() { - - public void run() { - - AuthorizationProvider.instance.set(new Caller(new UserInfo("test", new ArrayList()),"DEFAULT")); - - try { - - Client client = create(); - - if (logged) - client.addFilter(new LoggingFilter(System.err)); - - Builder builder = client.resource(address(path,port)) - .entity(body).header(scope_header, scope); - - for (Entry> header : headers.entrySet()) - for (Object value : header.getValue()) - builder.header(header.getKey(), value); - - if (method==DELETE) - builder.delete(); - else { - - System.err.println("making request @ "+address(path,port)); - - ClientResponse response = builder.method(method.name(),ClientResponse.class); - - //throws an exception if there response has error status - if (response.getStatus()>300) - throw new UniformInterfaceException(response); - - box.response=response; - } - - - } catch (UniformInterfaceException t) { - box.failure=t; - } - - latch.countDown(); - }; - }.start(); - - try { - - if (!latch.await(2000, MILLISECONDS)) - throw new RuntimeException("application has not responded in time"); - - } catch (InterruptedException e) { - throw new RuntimeException(e); - } - - if (box.failure !=null) - throw box.failure; - - else - return box.response; - - } - - private String address(String path, long port) { - - path = (path.isEmpty() || path.startsWith("/"))?path:"/"+path; - - return "http://localhost:" + port+ "/" + context_root+path; - } - -} diff --git a/src/test/java/app/SomeApp.java b/src/test/java/app/SomeApp.java deleted file mode 100644 index edc311d..0000000 --- a/src/test/java/app/SomeApp.java +++ /dev/null @@ -1,449 +0,0 @@ -package app; - -import static org.gcube.smartgears.Constants.configuration_file_path; -import static org.gcube.smartgears.Constants.extensions_file_path; -import static org.gcube.smartgears.Constants.ghn_home_property; -import static org.gcube.smartgears.Constants.handlers_file_path; -import static utils.TestUtils.context_root; -import static utils.TestUtils.context_root_path; -import static utils.TestUtils.location; -import static utils.TestUtils.servlet_name; - -import java.io.File; - -import org.apache.catalina.Wrapper; -import org.apache.catalina.core.StandardContext; -import org.apache.catalina.startup.Tomcat; -import org.apache.commons.io.FileUtils; -import org.apache.tomcat.util.scan.StandardJarScanner; -import org.gcube.informationsystem.publisher.ScopedPublisher; -import org.gcube.smartgears.Constants; -import org.gcube.smartgears.configuration.Mode; -import org.gcube.smartgears.configuration.application.ApplicationConfiguration; -import org.gcube.smartgears.configuration.application.ApplicationExtensions; -import org.gcube.smartgears.configuration.application.ApplicationHandlers; -import org.gcube.smartgears.configuration.application.DefaultApplicationConfiguration; -import org.gcube.smartgears.configuration.container.ContainerConfiguration; -import org.gcube.smartgears.configuration.container.Site; -import org.gcube.smartgears.context.application.ApplicationContext; -import org.gcube.smartgears.managers.ContainerManager; -import org.gcube.smartgears.provider.ProviderFactory; -import org.jboss.shrinkwrap.api.ShrinkWrap; -import org.jboss.shrinkwrap.api.asset.StringAsset; -import org.jboss.shrinkwrap.api.exporter.ZipExporter; -import org.jboss.shrinkwrap.api.spec.WebArchive; -import org.jboss.shrinkwrap.impl.base.path.BasicPath; - -import com.sun.jersey.api.client.ClientResponse; - -import utils.TestProvider; -import utils.TestUtils; - -/** - * Simulates a single-servlet application to be transformed into a gCube resource. - *

- *

    - *
  • uses a default configuration that can be customised (cf. {@link #configuration()}); - *
  • can be configured with the default handlers (cf. {@link #useDefaultHandlers()}) or custom ones ( - * {@link #handlers()}), including those that are not deployable through standard means, such as mocks ( - * {@link #bypassHandlerDeployment()}; - *
  • can be started to have a default behaviour when called, ({@link #start()}) or else a custom behaviour ( - * {@link #startWith(Runnable)}; - *
- * can be called in a default scope ({@link #call()} or in a specific scope ({@link #callIn(String)}). Calls are blocking but always - * configured and executed in a separate thread; - * - * @author Fabio Simeoni - * - */ -public class SomeApp { - - private final Tomcat tomcat = new Tomcat(); - - private WebArchive war = defaultWar(); - - private ContainerConfiguration containerConfiguration; - private ApplicationConfiguration configuration; - private ApplicationHandlers handlers = new ApplicationHandlers(); - private ApplicationExtensions extensions = new ApplicationExtensions(); - private TestProvider provider = new TestProvider(); - private boolean deployHandlers = true; - private boolean deployExtensions = true; - private boolean deployConfiguration = true; - private boolean clean=true; - - public SomeApp() { - - if (ContainerManager.instance!=null) - ContainerManager.instance.stop(true); - - tomcat.getConnector().setPort(0); - tomcat.setBaseDir(location); - - System.setProperty(ghn_home_property,location); - - containerConfiguration = defaultContainerConfiguration(); - configuration = defaultConfiguration(); - } - - /** - * Sets a {@link TestProvider} to resolve dependencies at runtime. - * - * @param provider the provider - */ - public void set(TestProvider provider) { - this.provider = provider; - } - - /** - * Runs the test with the state left by previous run. - *

- * Use only within a single test! - */ - public void dirtyRun() { - this.clean = false; - } - - /** - * Returns the configuration of the application. - *

- * The initial configuration is based on defaults, but can be changed and extended. - * - * @return the configuration - */ - public ApplicationConfiguration configuration() { - return configuration; - } - - /** - * Returns the configuration of the containerConfiguration. - *

- * The initial configuration is based on defaults, but can be changed and extended. - * - * @return the configuration - */ - public ContainerConfiguration containerConfiguration() { - return containerConfiguration; - } - - /** - * Returns the handlers that manage the application, none by default. - * - * @return the handlers - */ - public ApplicationHandlers handlers() { - return handlers; - } - - /** - * Avoids deployment of the configured handlers in the application's WAR. - *

- * The handlers will instead be directly available at runtime. - */ - public void bypassHandlerDeployment() { - - provider.use(handlers()); - deployHandlers = false; - } - - - /** - * Avoids resource configuration deployment. - */ - public void asExternal() { - - configuration.context(context_root_path); - containerConfiguration.app(configuration); - - bypassConfigurationDeployment(); - bypassExtensionsDeployment(); - bypassHandlerDeployment(); - } - - /** - * Avoids resource configuration deployment. - */ - public void withExternal(ApplicationConfiguration config) { - - config.context(context_root_path); - - containerConfiguration.app(config.context()).merge(config); - } - - public void bypassConfigurationDeployment() { - - deployConfiguration = false; - - } - - - public void usePublisher(ScopedPublisher publisher) { - - provider.use(publisher); - } - - /** - * Uses default handlers. - */ - public void useDefaultHandlers() { - - deployHandlers = false; - } - - - /** - * Returns the extensions of the application, none by default. - * - * @return the handlers - */ - public ApplicationExtensions extensions() { - return extensions; - } - - /** - * Uses default extensions. - */ - public void useDefaultExtensions() { - - deployExtensions = false; - } - - /** - * Avoids deployment of the configured extensions in the application's WAR. - *

- * The extensions will instead be directly available at runtime. - */ - public void bypassExtensionsDeployment() { - - provider.use(extensions()); - deployExtensions = false; - } - - /** - * Starts the application. - * - * @return the context of the application - */ - public ApplicationContext start() { - - return startWith(new Runnable() { - - @Override - public void run() { - System.err.println("test servlet invoked with no particular task"); - } - }); - } - - /** - * Starts the application, injecting test logic in its single servlet - * - * @param test test logic - * @return the context of the application - */ - public ApplicationContext startWith(Runnable test) { - - // install provider - ProviderFactory.testProvider(provider); - - if (clean) - cleanupInstallation(); - - installContainerConfiguration(); - - if (deployConfiguration) - deployConfiguration(); - - if (deployHandlers) - deployHandlers(); - - if (deployExtensions) - deployExtensions(); - - try { - - System.err.println("deploying with " + war.toString(true)); - - StandardContext ctx = (StandardContext) tomcat.addWebapp(context_root_path, warFile().getAbsolutePath()); - - // tells tomcat to look also for exploded directories such as this project's (finds initializer) - ((StandardJarScanner) ctx.getJarScanner()).setScanAllDirectories(true); - - //this starts webapp and always comes back - tomcat.start(); - - ApplicationContext context = provider.context; - - if (context==null) - throw new RuntimeException("app failed @ startup"); - - Wrapper webapp = (Wrapper) tomcat.getHost().findChild(context_root_path).findChild(servlet_name); - - if (webapp!=null) { - - webapp.setServlet(new TestServlet(test)); - - context.container().configuration().port(port()); - - containerConfiguration = context.container().configuration(); - } - - return context; - - } catch (Exception e) { - throw new RuntimeException(e); - } - - } - - /** - * Retuens true if the application was successfully start in the container. - * - * @return true if the application was successfully start in the container - */ - public boolean isActive() { - return tomcat.getHost().findChild("/" + context_root).findChild(servlet_name) != null; - } - - /** - * Makes a request to the application. - */ - - public String send(Request call) { - return call.make(port()).getEntity(String.class); - } - - /** - * Makes a request to the application. - */ - - public ClientResponse httpSend(Request call) { - return call.make(port()); - } - - - /** - * Stops the application - */ - public void stop() { - - try { - tomcat.stop(); - tomcat.destroy(); - - } catch (Exception e) { - System.err.println("WARNING: could not clearly stop container:"); - e.printStackTrace(); - } - } - - public File containerConfigurationFile() { - - return new File(location,Constants.container_configuraton_file_path); - } - // helpers - - /** - * Installs the container configuration. - */ - private void installContainerConfiguration() { - - TestUtils.serialise(containerConfiguration(),containerConfigurationFile()); - - } - - /** - * Includes the configuration in the application's WAR. - */ - private void deployConfiguration() { - - String xml = TestUtils.bind(configuration()); - - System.err.println("deploying with configuration:\n" + xml); - - war.addAsWebResource(new StringAsset(xml), new BasicPath(configuration_file_path)); - } - - /** - * Includes the handlers in the application's WAR. - */ - private void deployHandlers() { - - String xml = TestUtils.bind(handlers()); - - System.err.println("deploying with handlers:\n" + xml); - - war.addAsWebResource(new StringAsset(xml), new BasicPath(handlers_file_path)); - } - - /** - * Includes the extensions in the application's WAR. - */ - private void deployExtensions() { - - String xml = TestUtils.bind(extensions()); - - System.err.println("deploying with extensions:\n" + xml); - - war.addAsWebResource(new StringAsset(xml), new BasicPath(extensions_file_path)); - } - - private File warFile() { - - File warFile = new File(location, "test.war"); - - if (warFile.exists() && !warFile.delete()) - System.out.println("could not delete old deployment");; // seems safer than plain overwrite to avoid war corruption - - war.as(ZipExporter.class).exportTo(warFile, true); - - return warFile; - - } - - private WebArchive defaultWar() { - - WebArchive war = ShrinkWrap.create(WebArchive.class); - war.setWebXML(new File("src/test/java/app/web.xml")); - return war; - - } - - private ApplicationConfiguration defaultConfiguration() { - - return new DefaultApplicationConfiguration().mode(Mode.offline).serviceClass("test-class").name("test-app").version("1.0"); - - } - - private ContainerConfiguration defaultContainerConfiguration() { - - return new ContainerConfiguration().mode(Mode.offline).hostname("localhost").port(port()).infrastructure("gcube") - .site(new Site().country("it").location("rome").latitude("41.9000").longitude("12.5000")) - .property("test-prop1","foo") - .property("test-prop2","bar") - .publicationFrequency(5); - - } - - public int port() { - return tomcat.getConnector().getLocalPort(); - } - - private void cleanupInstallation() { - - System.out.println("cleaning installation in location "+location); - - File installation = new File(location); - - if (installation.exists()) - try { - FileUtils.deleteDirectory(installation); - } - catch(Exception e) { - throw new RuntimeException(e); - } - - installation.mkdirs(); - - } -} diff --git a/src/test/java/app/TestServlet.java b/src/test/java/app/TestServlet.java deleted file mode 100644 index b74bf33..0000000 --- a/src/test/java/app/TestServlet.java +++ /dev/null @@ -1,30 +0,0 @@ -package app; - -import java.io.IOException; - -import javax.servlet.ServletException; -import javax.servlet.annotation.WebServlet; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - - - -@WebServlet(name = "test", urlPatterns = "/test") -public class TestServlet extends HttpServlet { - - private static final long serialVersionUID = 1L; - - private Runnable test; - - public TestServlet(Runnable test) { - this.test=test; - } - - @Override - protected void doGet(HttpServletRequest request, - HttpServletResponse response) throws ServletException, IOException { - - test.run(); - } -} diff --git a/src/test/java/app/web.xml b/src/test/java/app/web.xml deleted file mode 100644 index 5199029..0000000 --- a/src/test/java/app/web.xml +++ /dev/null @@ -1,15 +0,0 @@ - - - test-app - - - test - app.TestServlet - - - - test - /* - - - \ No newline at end of file diff --git a/src/test/java/test/BinderTest.java b/src/test/java/test/BinderTest.java new file mode 100644 index 0000000..8c059c1 --- /dev/null +++ b/src/test/java/test/BinderTest.java @@ -0,0 +1,20 @@ +package test; + +import java.io.InputStream; + +import org.gcube.smartgears.configuration.container.ContainerConfiguration; +import org.gcube.smartgears.configuration.container.ContainerConfigurationBinder; +import org.junit.Test; + +public class BinderTest { + + + @Test + public void bindConfig() throws Exception { + + InputStream stream = BinderTest.class.getResourceAsStream("/container.ini"); + + ContainerConfiguration conf = new ContainerConfigurationBinder().load(stream); + System.out.println(conf.toString()); + } +} diff --git a/src/test/java/test/SmartgearsConfigurationTest.java b/src/test/java/test/SmartgearsConfigurationTest.java deleted file mode 100644 index 2d67dc8..0000000 --- a/src/test/java/test/SmartgearsConfigurationTest.java +++ /dev/null @@ -1,37 +0,0 @@ -package test; - -import static junit.framework.Assert.*; - -import java.io.ByteArrayInputStream; - -import org.gcube.smartgears.configuration.library.SmartGearsConfiguration; -import org.gcube.smartgears.configuration.library.SmartGearsConfigurationBinder; -import org.junit.Test; - -public class SmartgearsConfigurationTest { - - @Test - public void configurationBinds() throws Exception { - - String xml = ""; - - SmartGearsConfigurationBinder binder = new SmartGearsConfigurationBinder(); - - SmartGearsConfiguration bound = binder.bind(new ByteArrayInputStream(xml.getBytes())); - - bound.validate(); - - String version = bound.version(); - assertEquals("1.0.0-SNAPSHOT",version); - - assertEquals(sampleSmartgearsConfiguration(),bound); - - - } - - private SmartGearsConfiguration sampleSmartgearsConfiguration() { - - return new SmartGearsConfiguration().version("1.0.0-SNAPSHOT"); - - } -} diff --git a/src/test/java/test/application/AppLifecycleTest.java b/src/test/java/test/application/AppLifecycleTest.java deleted file mode 100644 index 8d339ea..0000000 --- a/src/test/java/test/application/AppLifecycleTest.java +++ /dev/null @@ -1,36 +0,0 @@ -package test.application; - -import static org.junit.Assert.*; - -import org.gcube.smartgears.context.application.ApplicationContext; -import org.gcube.smartgears.context.container.ContainerContext; -import org.gcube.smartgears.handlers.application.lifecycle.ProfileManager; -import org.gcube.smartgears.lifecycle.application.ApplicationState; -import org.gcube.smartgears.lifecycle.container.ContainerState; -import org.junit.Test; - -import app.SomeApp; - -public class AppLifecycleTest { - - @Test - public void applicationGoesDownIfContainerDoes() { - - SomeApp app = new SomeApp(); - - app.handlers().set(new ProfileManager()); - - ApplicationContext actx = app.start(); - - assertEquals(ApplicationState.active,actx.lifecycle().state()); - - ContainerContext ctx = actx.container(); - - assertEquals(ContainerState.active,ctx.lifecycle().state()); - - ctx.lifecycle().moveTo(ContainerState.stopped); - - assertEquals(ApplicationState.stopped,actx.lifecycle().state()); - } - -} diff --git a/src/test/java/test/application/CallValidationTest.java b/src/test/java/test/application/CallValidationTest.java deleted file mode 100644 index a980908..0000000 --- a/src/test/java/test/application/CallValidationTest.java +++ /dev/null @@ -1,213 +0,0 @@ -package test.application; - -import static app.Request.request; -import static junit.framework.Assert.assertEquals; -import static junit.framework.Assert.fail; -import static org.gcube.smartgears.handlers.application.request.RequestError.application_failed_error; -import static org.gcube.smartgears.handlers.application.request.RequestError.application_unavailable_error; -import static org.gcube.smartgears.handlers.application.request.RequestError.invalid_request_error; -import static org.gcube.smartgears.handlers.application.request.RequestError.request_not_authorized_error; -import static org.gcube.smartgears.lifecycle.application.ApplicationState.failed; -import static org.gcube.smartgears.lifecycle.application.ApplicationState.stopped; -import static utils.TestUtils.scope; - -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; - -import org.gcube.common.authorization.library.provider.SecurityTokenProvider; -import org.gcube.smartgears.Constants; -import org.gcube.smartgears.configuration.application.Exclude; -import org.gcube.smartgears.context.application.ApplicationContext; -import org.gcube.smartgears.handlers.application.lifecycle.ProfileManager; -import org.gcube.smartgears.handlers.application.request.RequestValidator; -import org.junit.Test; - -import app.SomeApp; - -import com.sun.jersey.api.client.UniformInterfaceException; - -public class CallValidationTest { - - - @Test - public void rejectsCallsWhenServiceIsInactive() { - - SomeApp app = new SomeApp(); - - app.handlers().set(new ProfileManager()).set(new RequestValidator()); - - - Runnable test = new Runnable() { - - @Override - public void run() { - fail("call should have been rejected"); - } - }; - - ApplicationContext context = app.startWith(test); - - context.lifecycle().moveTo(stopped); - - try { - app.send(request()); - } - catch(UniformInterfaceException e) { - assertEquals(application_unavailable_error.code(), e.getResponse().getStatus()); - } - - - context.lifecycle().moveTo(failed); - - try { - app.send(request()); - } - catch(UniformInterfaceException e) { - assertEquals(application_failed_error.code(), e.getResponse().getStatus()); - - } - - } - - @Test - public void rejectsCallsWithoutScope() throws Throwable { - - SomeApp app = new SomeApp(); - - app.handlers().set(new ProfileManager()).set(new RequestValidator()); - - app.start(); - - try { - app.send(request().inScope(null));; //call in no scope - fail(); - } - catch(UniformInterfaceException e) { - assertEquals(request_not_authorized_error.code(), e.getResponse().getStatus()); - } - - } - - @Test - public void rejectsCallsWithBadScope() throws Throwable { - - SomeApp app = new SomeApp(); - - app.handlers().set(new ProfileManager()).set(new RequestValidator()); - - app.start(); - - try { - app.send(request().inScope("/bad/scope")); //call in no scope - fail(); - } - catch(UniformInterfaceException e) { - assertEquals(invalid_request_error.code(), e.getResponse().getStatus()); - } - - } - - @Test - public void propagatesScope() throws Throwable { - - SomeApp app = new SomeApp(); - - app.handlers().set(new ProfileManager()).set(new RequestValidator()); - - Runnable test = new Runnable() { - - @Override - public void run() { - assertEquals(scope,SecurityTokenProvider.instance.get()); - } - }; - - app.startWith(test); - - app.send(request()); - - } - - @Test - public void respectsAllExcludeWildCard() throws Throwable { - - SomeApp app = new SomeApp(); - - app.configuration().excludes().add(new Exclude(Constants.WILDCARD)); - - app.handlers().set(new ProfileManager()).set(new RequestValidator()); - - final CountDownLatch latch = new CountDownLatch(1); - - Runnable test = new Runnable() { - - @Override - public void run() { - latch.countDown(); - } - }; - - app.startWith(test); - - app.send(request().inScope(null)); - - latch.await(500,TimeUnit.MILLISECONDS); - - } - - @Test - public void respectsExcludeWildCard() throws Throwable { - - SomeApp app = new SomeApp(); - - app.configuration().excludes().add(new Exclude("/path"+Constants.WILDCARD)); - - app.handlers().set(new ProfileManager()).set(new RequestValidator()); - - final CountDownLatch latch = new CountDownLatch(1); - - Runnable test = new Runnable() { - - @Override - public void run() { - latch.countDown(); - } - }; - - app.startWith(test); - - app.send(request().at("path/test").inScope(null)); - - latch.await(500,TimeUnit.MILLISECONDS); - - } - - - @Test - public void respectsExactExclude() throws Throwable { - - SomeApp app = new SomeApp(); - - app.configuration().excludes().add(new Exclude("/path")); - - app.handlers().set(new ProfileManager()).set(new RequestValidator()); - - final CountDownLatch latch = new CountDownLatch(1); - - Runnable test = new Runnable() { - - @Override - public void run() { - latch.countDown(); - } - }; - - app.startWith(test); - - app.send(request().at("path").inScope(null)); - - latch.await(500,TimeUnit.MILLISECONDS); - - } - -} diff --git a/src/test/java/test/application/ConfigurationTest.java b/src/test/java/test/application/ConfigurationTest.java deleted file mode 100644 index c9d6d81..0000000 --- a/src/test/java/test/application/ConfigurationTest.java +++ /dev/null @@ -1,114 +0,0 @@ -package test.application; - -import static junit.framework.Assert.assertEquals; -import static junit.framework.Assert.assertNotNull; - -import java.io.ByteArrayInputStream; - -import org.gcube.smartgears.configuration.Mode; -import org.gcube.smartgears.configuration.application.ApplicationConfiguration; -import org.gcube.smartgears.configuration.application.ApplicationConfigurationBinder; -import org.gcube.smartgears.configuration.application.ApplicationExtensions; -import org.gcube.smartgears.configuration.application.DefaultApplicationConfiguration; -import org.gcube.smartgears.configuration.application.Include; -import org.gcube.smartgears.extensions.ApplicationExtension; -import org.gcube.smartgears.persistence.DefaultPersistence; -import org.junit.Test; - -public class ConfigurationTest { - - @Test - public void configurationBinds() throws Exception { - - String xml = "" + - "name" + - "class" + - "version" + - "desc" + - "start/scope"+ - "another/start/scope"+ - "/pathBis" + - "" + - ""; - - - ApplicationConfigurationBinder binder = new ApplicationConfigurationBinder(); - - ApplicationConfiguration bound = binder.bind(new ByteArrayInputStream(xml.getBytes())); - - - System.out.println(bound); - - assertEquals(sampleConfiguration(),bound); - - } - - - @Test - public void extensionsBind() throws Exception { - - String xml = "" + - "" + - ""; - - - ApplicationConfigurationBinder binder = new ApplicationConfigurationBinder(); - - ApplicationExtensions bound = binder.bindExtensions(new ByteArrayInputStream(xml.getBytes())); - - assertNotNull(bound.extensions()); - assertEquals(1,bound.extensions().size()); - - ApplicationExtension ext = bound.extensions().get(0); - assertEquals("custom",ext.name()); - assertEquals("custom",ext.mapping()); - - - } - - - /*@Test - public void configurationsMerge() throws Exception { - - ApplicationConfiguration original = sampleConfiguration(); - - ApplicationConfiguration one = sampleConfiguration(); - - ApplicationConfiguration two = new DefaultApplicationConfiguration(); - two.mode(Mode.online); - two.persistence(new DefaultPersistence(new File(".").getAbsolutePath())); - two.startScopes("yet/another/one"); - - one.merge(two); - - assertEquals(one.mode(), two.mode()); - assertEquals(one.name(), original.name()); - assertEquals(one.persistence(), two.persistence()); - - Set merged = new HashSet<>(original.startScopes()); - - merged.addAll(two.startScopes()); - - assertEquals(merged,one.startScopes()); - - }*/ - - //helpers - - private ApplicationConfiguration sampleConfiguration() { - - - return new DefaultApplicationConfiguration() - .mode(Mode.offline) - .context("ctx") - .name("name") - .serviceClass("class") - .includes(new Include("/pathBis")) - .version("version") - .description("desc") - .persistence(new DefaultPersistence("target")); - - } - - -} diff --git a/src/test/java/test/application/ControllerTest.java b/src/test/java/test/application/ControllerTest.java deleted file mode 100644 index cbdbb97..0000000 --- a/src/test/java/test/application/ControllerTest.java +++ /dev/null @@ -1,277 +0,0 @@ -package test.application; - -import static app.Request.*; -import static org.gcube.smartgears.Constants.*; -import static org.gcube.smartgears.extensions.ApiResource.*; -import static org.gcube.smartgears.extensions.HttpExtension.Method.*; -import static org.gcube.smartgears.handlers.application.request.RequestError.*; -import static org.junit.Assert.*; - -import java.io.IOException; - -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import org.gcube.smartgears.Constants; -import org.gcube.smartgears.extensions.ApiResource; -import org.gcube.smartgears.extensions.ApiSignature; -import org.gcube.smartgears.extensions.HttpController; -import org.gcube.smartgears.extensions.HttpExtension; -import org.junit.Test; - -import app.Request; -import app.SomeApp; - -import com.sun.jersey.api.client.ClientResponse; -import com.sun.jersey.api.client.UniformInterfaceException; - -public class ControllerTest { - - String name = "name"; - String extension_path = "/ext"; - String extension_mapping = "/ext/*"; - String resource_path = "/resource"; - - @Test - public void dispatchesToResource() { - - // returns a given type - ApiSignature signature = handles(resource_path).with(method(GET).produces("text/plain")); - - // requires same type - Request request = request().at(resource()).with(accept, "text/plain"); - - SomeApp app = startAppWith(signature); - - app.send(request); - } - - @Test - public void toleratesTrainingSlashes() { - - // returns a given type - ApiSignature signature = handles(resource_path).with(method(GET).produces("text/plain")); - - // requires same type - Request request = request().at(resource()).with(accept, "text/plain"); - - SomeApp app = startAppWith(signature); - - app.send(request); - } - - @Test - public void handlesUnknownResources() { - - ApiSignature signature = handles(resource_path); - - // points to not existing resource - Request request = request().at(resource() + "/bad"); - - SomeApp app = startAppWith(signature); - - try { - app.send(request); - fail(); - } catch (UniformInterfaceException e) { - assertEquals(resource_notfound_error.code(), e.getResponse().getStatus()); - } - } - - @Test - public void handlesUnsupportedMethods() { - - ApiSignature signature = handles(resource_path).with(method(GET)).with(method(PUT)); - - Request request = request().at(resource()).using(POST); - - SomeApp app = startAppWith(signature); - - try { - app.send(request); - fail(); - } catch (UniformInterfaceException e) { - assertEquals(method_unsupported_error.code(), e.getResponse().getStatus()); - assertNotNull(e.getResponse().getHeaders().toString(),e.getResponse().getHeaders().get(allow)); - } - } - - @Test - public void enforcesAcceptHeaders() { - - ApiSignature signature = handles(resource_path).with(method(GET).produces("text/plain")); - - Request request = request().at(resource()).with(accept, "text/xml"); - - SomeApp app = startAppWith(signature); - - try { - app.send(request); - fail(); - } catch (UniformInterfaceException e) { - assertEquals(outgoing_contenttype_unsupported_error.code(), e.getResponse().getStatus()); - - } - } - - @Test - public void enforcesAcceptHeadersEvenWhenResourceDeclaresNone() { - - ApiSignature signature = handles(resource_path).with(method(GET)); - - Request request = request().at(resource()).with(accept, "text/xml"); - - SomeApp app = startAppWith(signature); - - try { - app.send(request); - fail(); - } catch (UniformInterfaceException e) { - assertEquals(outgoing_contenttype_unsupported_error.code(), e.getResponse().getStatus()); - } - } - - @Test - public void enforcesMultiValuedAcceptHeader() { - - ApiSignature signature = handles(resource_path).with(method(GET).produces("text/plain")); - - Request request = request().at(resource()).with(accept, "text/xml").with(accept,"text/plain"); - - SomeApp app = startAppWith(signature); - - app.send(request); - - } - - @Test - public void setsContentTypeIfUnsetAndUnambiguous() { - - ApiSignature signature = handles(resource_path).with(method(GET).produces("text/plain")); - - Request request = request().at(resource()).with(accept, "text/plain"); - - SomeApp app = startAppWith(signature); - - ClientResponse response = app.httpSend(request); - - assertTrue(response.getHeaders().get(content_type).get(0).contains("text/plain")); - } - - @Test - public void doesntSetContentTypeIfUnsetButAmbiguous() { - - ApiSignature signature = handles(resource_path).with(method(GET).produces("text/plain","text/xml")); - - Request request = request().at(resource()).with(accept, "text/plain"); - - SomeApp app = startAppWith(signature); - - ClientResponse response = app.httpSend(request); - - System.out.println(response.getHeaders()); - - assertNull(response.getHeaders().get(content_type)); - - } - - - @Test - public void enforcesMultiValuedContentTypeHeader() { - - ApiSignature signature = handles(resource_path).with(method(POST).accepts("application/xml")); - - Request request = request().at(resource()).using(POST).with(content_type, "text/xml").with(content_type,"text/plain"); - - SomeApp app = startAppWith(signature); - - try { - app.send(request); - fail(); - } catch (UniformInterfaceException e) { - assertEquals(incoming_contenttype_unsupported_error.code(), e.getResponse().getStatus()); - } - } - - @Test - public void acceptsContentTypeHeadersWhenResourceDeclaresNone() { - - ApiSignature signature = handles(resource_path).with(method(POST)); - - Request request = request().at(resource()).using(POST).with(content_type, "text/xml"); - - SomeApp app = startAppWith(signature); - - app.httpSend(request); - - } - - - - ///////////////////////////////// helpers - - private String resource() { - return Constants.root_mapping + extension_path + resource_path; - } - - SomeApp startAppWith(ApiSignature signature) { - - SomeApp app = new SomeApp(); - - app.extensions().set(controllerWith(signature)); - - app.bypassExtensionsDeployment(); - app.bypassHandlerDeployment(); - - app.start(); - - return app; - } - - - - @SuppressWarnings("serial") - HttpExtension controllerWith(final ApiSignature signature) { - return new HttpController(name, extension_mapping) { - - { - addResources(new ApiResource(signature) { - - @Override - public void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, - IOException { - if (!supports(Method.valueOf(req.getMethod()))) - super.doGet(req, resp); - else - resp.getWriter().write(req.getMethod() + " invoked @ " + signature.mapping()); - } - - @Override - public void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, - IOException { - if (!supports(Method.valueOf(req.getMethod()))) - super.doPost(req, resp); - else - resp.getWriter().write(req.getMethod() + " invoked @ " + signature.mapping()); - } - - @Override - public void doPut(HttpServletRequest req, HttpServletResponse resp) throws ServletException, - IOException { - if (!supports(Method.valueOf(req.getMethod()))) - super.doPut(req, resp); - else - resp.getWriter().write(req.getMethod() + " invoked @ " + signature.mapping()); - } - - }); - } - - @Override - public String toString() { - return "SUT controller"; - } - }; - } -} diff --git a/src/test/java/test/application/ExtensionsTest.java b/src/test/java/test/application/ExtensionsTest.java deleted file mode 100644 index 030fb8a..0000000 --- a/src/test/java/test/application/ExtensionsTest.java +++ /dev/null @@ -1,185 +0,0 @@ -package test.application; - -import static app.Request.request; -import static junit.framework.Assert.assertEquals; -import static junit.framework.Assert.assertNotNull; -import static junit.framework.Assert.fail; -import static org.gcube.smartgears.handlers.application.request.RequestError.invalid_request_error; -import static org.gcube.smartgears.lifecycle.application.ApplicationState.failed; - -import java.io.IOException; - -import javax.servlet.ServletException; -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; -import javax.xml.bind.annotation.XmlRootElement; - -import org.gcube.smartgears.Constants; -import org.gcube.smartgears.context.application.ApplicationContext; -import org.gcube.smartgears.extensions.ApplicationExtension; -import org.gcube.smartgears.extensions.HttpExtension; -import org.gcube.smartgears.extensions.resource.RemoteResource; -import org.gcube.smartgears.handlers.application.request.RequestError; -import org.junit.Test; - -import app.SomeApp; - -import com.sun.jersey.api.client.UniformInterfaceException; - -public class ExtensionsTest { - - String name = "name"; - String extension_path="/ext"; - - - @Test - public void areInstalledAndInitialised() { - - - final String response = "output"; - - @SuppressWarnings("serial") - ApplicationExtension extension = new HttpExtension(name,extension_path) { - - @Override - public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException { - assertNotNull(context()); //init has been invoked - res.getWriter().write(response); - } - - }; - - - - SomeApp app = new SomeApp(); - - app.extensions().set(extension); - - //we're only testing correct installation, not configuration now anything else - app.bypassExtensionsDeployment(); - - app.start(); - - String actual = app.send(request().at(Constants.root_mapping+extension_path)); - - assertEquals(response,actual); - } - - @SuppressWarnings("serial") - @XmlRootElement(name="unknown") - static class UnknownExtension extends HttpExtension { - - UnknownExtension() {} - - public UnknownExtension(String name, String mapping) { - super(name, mapping); - } - - @Override - public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException { - } - } - - @Test - public void failAppIfNotConfigured() { - - SomeApp app = new SomeApp(); - - app.bypassHandlerDeployment(); - - app.extensions().set(new UnknownExtension(name,extension_path)); - - ApplicationContext context= app.start(); - - assertEquals(failed,context.lifecycle().state()); - - } - - @Test - public void failAppIfConfiguredBadly() { - - SomeApp app = new SomeApp(); - - RemoteResource extension = new RemoteResource(); - extension.name(""); - extension.mapping(""); - - app.extensions().set(extension); - - app.bypassHandlerDeployment(); - - ApplicationContext context= app.start(); - - assertEquals(failed,context.lifecycle().state()); - - } - - - @Test - public void throwErrorsConvertedInHttpResponses() { - - - final RequestError error = invalid_request_error; - - @SuppressWarnings("serial") - ApplicationExtension extension = new HttpExtension(name,extension_path) { - - @Override - public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException { - error.fire(); - } - - }; - - SomeApp app = new SomeApp(); - - app.extensions().set(extension); - - //we're only testing correct installation, not configuration now anything else - app.bypassExtensionsDeployment(); - - app.start(); - - try { - app.send(request().at(Constants.root_mapping+extension_path)); - fail(); - } - catch(UniformInterfaceException e) { - - assertEquals(error.code(),e.getResponse().getStatus()); - } - - } - - @Test - public void areManagedLikeNativeServlets() { - - @SuppressWarnings("serial") - ApplicationExtension extension = new HttpExtension(name,extension_path) { - @Override - public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException { - } - }; - - SomeApp app = new SomeApp(); - - app.extensions().set(extension); - - app.bypassExtensionsDeployment(); - - //installs default filters - app.useDefaultHandlers(); - - app.start(); - - //call in no scope - try { - app.send(request().at(Constants.root_mapping+extension_path).inScope(null)); - fail(); - } - catch(UniformInterfaceException e) { - - assertEquals(e.getResponse().getEntity(String.class),invalid_request_error.code(),e.getResponse().getStatus()); - } - } -} diff --git a/src/test/java/test/application/ProfileManagementTest.java b/src/test/java/test/application/ProfileManagementTest.java deleted file mode 100644 index bed3475..0000000 --- a/src/test/java/test/application/ProfileManagementTest.java +++ /dev/null @@ -1,74 +0,0 @@ -package test.application; - -import static junit.framework.Assert.*; -import static org.gcube.smartgears.Constants.*; - -import java.io.File; - -import org.gcube.common.resources.gcore.GCoreEndpoint; -import org.gcube.common.resources.gcore.Resources; -import org.gcube.smartgears.context.application.ApplicationContext; -import org.gcube.smartgears.handlers.application.lifecycle.ProfileManager; -import org.gcube.smartgears.lifecycle.application.ApplicationLifecycle; -import org.junit.BeforeClass; -import org.junit.Test; - -import app.SomeApp; - -public class ProfileManagementTest { - - public static ApplicationContext ctx; - - @BeforeClass - public static void startApp() { - - SomeApp app = new SomeApp(); - - app.handlers().set(new ProfileManager()); - - ctx = app.start(); - - } - - @Test - public void createsStoresAndPublishesAValidProfile() throws Exception { - - GCoreEndpoint profile = ctx.profile(GCoreEndpoint.class); - - assertNotNull(profile); - - //assert profile has been created - File file = ctx.configuration().persistence().file(profile_file_path); - assertTrue(file.exists()); - - assertFalse(profile.scopes().isEmpty()); - - Resources.validate(profile); - - //assert status matches lifecycle's current state - ApplicationLifecycle lc = ctx.lifecycle(); - - assertEquals(profile.profile().deploymentData().status(),lc.state().remoteForm()); - - } - - @Test - public void loadsAndUpdatesProfile() throws Exception { - - SomeApp runtwice = new SomeApp(); - - runtwice.handlers().set(new ProfileManager()); - - runtwice.dirtyRun(); - - ApplicationContext ctx = runtwice.start(); - - - GCoreEndpoint profile = ctx.profile(GCoreEndpoint.class); - - assertNotNull(profile); - - Resources.validate(profile); - } - -} diff --git a/src/test/java/test/application/RemoteResourceTest.java b/src/test/java/test/application/RemoteResourceTest.java deleted file mode 100644 index 03188a4..0000000 --- a/src/test/java/test/application/RemoteResourceTest.java +++ /dev/null @@ -1,129 +0,0 @@ -package test.application; - -import static app.Request.request; -import static org.gcube.smartgears.Constants.application_xml; -import static org.gcube.smartgears.Constants.content_type; -import static org.gcube.smartgears.extensions.HttpExtension.Method.GET; -import static org.gcube.smartgears.extensions.HttpExtension.Method.POST; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -import java.io.StringReader; - -import javax.xml.bind.JAXBContext; - -import org.gcube.common.resources.gcore.GCoreEndpoint; -import org.gcube.common.resources.gcore.Resources; -import org.gcube.smartgears.Constants; -import org.gcube.smartgears.context.application.ApplicationContext; -import org.gcube.smartgears.extensions.resource.ConfigurationResource; -import org.gcube.smartgears.extensions.resource.FrontPageResource; -import org.gcube.smartgears.extensions.resource.LifecycleResource; -import org.gcube.smartgears.extensions.resource.LifecycleResource.State; -import org.gcube.smartgears.extensions.resource.ProfileResource; -import org.gcube.smartgears.lifecycle.application.ApplicationState; -import org.junit.BeforeClass; -import org.junit.Ignore; -import org.junit.Test; - -import app.Request; -import app.SomeApp; - -public class RemoteResourceTest { - - static final String path = "/resource"; - static JAXBContext jaxb; - static ApplicationContext context; - - static SomeApp app; - - @BeforeClass - public static void setup() throws Exception { - - jaxb = JAXBContext.newInstance(State.class); - - app = new SomeApp(); - - app.useDefaultHandlers(); - app.useDefaultExtensions(); - - context = app.start(); - } - - @Test - public void showsFrontpage() throws Exception { - - // unscoped request - Request request = request().at(resource(FrontPageResource.mapping)).inScope(null); - - app.send(request); - - //Thread.sleep(50000); enable to check interactively in browser - } - - @Test - public void showsConfiguration() throws Exception { - - //unscoped request - Request request = request().at(resource(ConfigurationResource.mapping)).inScope(null); - - app.send(request); - } - - @Test - public void showsProfile() throws Exception { - - //unscoped request - Request request = request().at(resource(ProfileResource.mapping)).inScope(null); - - String outcome = app.send(request); - - GCoreEndpoint profile = Resources.unmarshal(GCoreEndpoint.class, new StringReader(outcome)); - - assertEquals(context.profile(GCoreEndpoint.class).id(), profile.id()); - assertEquals(context.profile(GCoreEndpoint.class).profile().deploymentData().status(), profile.profile().deploymentData().status()); - } - - - - - - @Test - public void currentState() throws Exception { - - Request request = request().at(resource(LifecycleResource.mapping)).using(GET).inScope(null); - - String outcome = app.send(request); - - State state = (State) jaxb.createUnmarshaller().unmarshal(new StringReader(outcome)); - - assertEquals(context.lifecycle().state(),ApplicationState.valueOf(state.value)); - - } - - @Ignore - @Test - public void changeState() throws Exception { - - ApplicationState newstate = ApplicationState.stopped; - - assertFalse(context.lifecycle().state()==newstate); - - Request request = request().at(resource(LifecycleResource.mapping)).using(POST).inScope(null) - .with(content_type, application_xml).with("stopped"); - - app.httpSend(request); - - assertTrue(context.lifecycle().state()==newstate); - - request = request().at(resource(LifecycleResource.mapping)).using(POST).inScope(null) - .with(content_type, application_xml).with("active"); - - } - - // helper - private String resource(String resource) { - return Constants.root_mapping + path + resource; - } -} diff --git a/src/test/java/test/application/StartupTest.java b/src/test/java/test/application/StartupTest.java deleted file mode 100644 index aecc38f..0000000 --- a/src/test/java/test/application/StartupTest.java +++ /dev/null @@ -1,231 +0,0 @@ -package test.application; - -import static app.Request.request; -import static org.gcube.smartgears.Constants.profile_file_path; -import static org.gcube.smartgears.lifecycle.application.ApplicationState.active; -import static org.gcube.smartgears.lifecycle.application.ApplicationState.failed; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.isA; -import static org.mockito.Mockito.doThrow; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import java.io.File; - -import org.gcube.common.resources.gcore.Resource; -import org.gcube.informationsystem.publisher.ScopedPublisher; -import org.gcube.informationsystem.publisher.exception.RegistryNotFoundException; -import org.gcube.smartgears.Constants; -import org.gcube.smartgears.configuration.application.ApplicationConfiguration; -import org.gcube.smartgears.configuration.application.DefaultApplicationConfiguration; -import org.gcube.smartgears.context.application.ApplicationContext; -import org.gcube.smartgears.handlers.application.ApplicationEvent; -import org.gcube.smartgears.handlers.application.ApplicationLifecycleEvent.Start; -import org.gcube.smartgears.handlers.application.ApplicationLifecycleHandler; -import org.gcube.smartgears.handlers.application.RequestHandler; -import org.gcube.smartgears.persistence.DefaultPersistence; -import org.junit.After; -import org.junit.Test; -import org.mockito.Matchers; -import org.mockito.Mockito; - -import app.SomeApp; -import utils.TestUtils.Box; - -public class StartupTest { - - SomeApp app = new SomeApp(); - - @After - public void teardown() { - app.stop(); - } - - @Test - public void succeedsWithDefaults() throws Exception { - - - app.useDefaultHandlers(); - app.useDefaultExtensions(); - - ApplicationContext ctx = app.start(); - - assertEquals(active,ctx.lifecycle().state()); - - //profile is shared in servlet context - assertEquals(ctx,ctx.application().getAttribute(Constants.context_attribute)); - - } - - @Test - public void stillStoresProfileWhenPublicationFails() throws Exception { - - app.useDefaultHandlers(); - - ScopedPublisher failingPublisher = Mockito.mock(ScopedPublisher.class); - when(failingPublisher.create(any(Resource.class), Matchers.anyListOf(String.class))).thenThrow(new RegistryNotFoundException()); - - app.usePublisher(failingPublisher); - - ApplicationContext ctx = app.start(); - - Thread.sleep(100); //a little bit of time for failure to propagate - - //application has failed - assertEquals(failed,ctx.lifecycle().state()); - - //profile has been created - File file = ctx.configuration().persistence().file(profile_file_path); - assertTrue(file.exists()); - - } - - @Test - @SuppressWarnings("all") - public void invokesLifecycleHandlers() { - - ApplicationLifecycleHandler witness = mock(ApplicationLifecycleHandler.class); - - app.handlers().set(witness); - - //as we're using mocks, let us bypass JAXB configuration mechanisms - app.bypassHandlerDeployment(); - - app.start(); - - verify(witness).onEvent(any(ApplicationEvent.class)); - } - - @Test - @SuppressWarnings("all") - public void registersRequestsHandlers() { - - Box handlerIsInvoked = new Box(); - - RequestHandler witness = mock(RequestHandler.class); - - app.handlers().set(witness); - - app.bypassHandlerDeployment(); - - app.start(); - - app.send(request()); - - //invoked for request and response - verify(witness,times(2)).onEvent(isA(ApplicationEvent.class)); - } - - //@Ignore //inexplicable sometimes fails as configuration is not removed - @Test - public void failsIfConfigurationIsInvalid() { - - app.configuration().name(null).serviceClass(null).description(null).version(null).persistence(null); - - ApplicationContext ctx = app.start(); - - assertEquals(failed,ctx.lifecycle().state()); - } - - @Test - public void failsIfHandlerFails() throws Throwable { - - ApplicationLifecycleHandler failingHandler = mock(ApplicationLifecycleHandler.class); - doThrow(new RuntimeException("simulated handler failure")).when(failingHandler).onEvent(isA(Start.class)); - - app.handlers().set(failingHandler); - - app.bypassHandlerDeployment(); - - ApplicationContext ctx = app.start(); - - assertEquals(failed,ctx.lifecycle().state()); - - } - - @Test - public void canUseExternalConfiguration() { - - app.asExternal(); - - app.start(); - - assertTrue(app.isActive()); - } - - - @Test - public void canUseMergedConfiguration() { - - ApplicationConfiguration config = new DefaultApplicationConfiguration(); - config.persistence(new DefaultPersistence(new File(".").getAbsolutePath())); - - ApplicationContext context = app.start(); - - assertTrue(app.isActive()); - - app.withExternal(config); - - assertEquals(config.persistence(),context.configuration().persistence()); - - } - - - @Test - public void failsIfAllStartScopesAreInvalid() throws Exception { - - ApplicationConfiguration config = new DefaultApplicationConfiguration(); - - //config.startScopes("bad/scope","even/badder"); - - app.useDefaultHandlers(); - - ApplicationContext context = app.start(); - - app.withExternal(config); - - assertEquals(failed,context.lifecycle().state()); - - - - } - - @Test - public void canStartInVreScope() throws Exception { - - ApplicationConfiguration config = new DefaultApplicationConfiguration(); - - //tring vre = "/"+app.containerConfiguration().infrastructure()+"/"+app.containerConfiguration().startVOs().get(0)+"/vre"; - - //config.startScopes(vre,"/bad/scope"); - - app.useDefaultHandlers(); - - ApplicationContext context = app.start(); - - app.withExternal(config); - - assertEquals(active,context.lifecycle().state()); - - //Set runningScopes = new HashSet<>(context.profile(GCoreEndpoint.class).scopes().asCollection()); - - //assertEquals(singleton(vre),runningScopes); - - - - - } - - - @Test(expected=RuntimeException.class) - public void failsIfConfigurationIsMissing() { - - app.bypassConfigurationDeployment(); - - app.start(); - } -} diff --git a/src/test/java/test/container/ConfigurationTest.java b/src/test/java/test/container/ConfigurationTest.java deleted file mode 100644 index 0f29ef6..0000000 --- a/src/test/java/test/container/ConfigurationTest.java +++ /dev/null @@ -1,71 +0,0 @@ -package test.container; - -import static junit.framework.Assert.assertEquals; -import static junit.framework.Assert.assertTrue; - -import java.io.ByteArrayInputStream; -import java.util.Arrays; -import java.util.List; - -import org.gcube.smartgears.configuration.Mode; -import org.gcube.smartgears.configuration.application.ApplicationConfiguration; -import org.gcube.smartgears.configuration.application.DefaultApplicationConfiguration; -import org.gcube.smartgears.configuration.container.ContainerConfiguration; -import org.gcube.smartgears.configuration.container.ContainerConfigurationBinder; -import org.gcube.smartgears.configuration.container.Site; -import org.gcube.smartgears.persistence.DefaultPersistence; -import org.junit.Test; - -public class ConfigurationTest { - - @Test - public void containerConfigurationBinds() throws Exception { - - String appXml = "" + "name" + "class" - + "version" + "desc" + "" - + ""; - - String xml = "" - + "localhost" - + "8080" - + "gcube" - + "true " - +"token1" + "token2" + "" + appXml + "" - + "it" + "rome" + "41.9000" - + "12.5000" + "" + "" - + "" + "30" - + ""; - - ContainerConfigurationBinder binder = new ContainerConfigurationBinder(); - - ContainerConfiguration bound = binder.bind(new ByteArrayInputStream(xml.getBytes())); - - bound.validate(); - - List scopes = bound.startTokens(); - - assertTrue(scopes.contains("token1")); - assertTrue(scopes.contains("token2")); - - assertEquals(sampleContainerConfiguration(), bound); - - } - - private ContainerConfiguration sampleContainerConfiguration() { - - return new ContainerConfiguration().mode(Mode.offline).hostname("localhost").port(8080).infrastructure("gcube") - .startTokens(Arrays.asList("token1", "token2")) - .site(new Site().country("it").location("rome").latitude("41.9000").longitude("12.5000")) - .property("prop1", "val1").property("prop2", "val2").publicationFrequency(30) - .app(sampleAppConfiguration()).authorizeChildrenContext(true) - .persistence(new DefaultPersistence("target")); - - } - - private ApplicationConfiguration sampleAppConfiguration() { - - return new DefaultApplicationConfiguration().mode(Mode.offline).name("name").serviceClass("class") - .version("version").description("desc").persistence(new DefaultPersistence("target")); - - } -} diff --git a/src/test/java/test/container/ContainerLifecycleTest.java b/src/test/java/test/container/ContainerLifecycleTest.java deleted file mode 100644 index 91a2cf0..0000000 --- a/src/test/java/test/container/ContainerLifecycleTest.java +++ /dev/null @@ -1,71 +0,0 @@ -package test.container; - -import static org.junit.Assert.*; - -import org.gcube.smartgears.context.application.ApplicationContext; -import org.gcube.smartgears.context.container.ContainerContext; -import org.gcube.smartgears.lifecycle.application.ApplicationState; -import org.gcube.smartgears.lifecycle.container.ContainerState; -import org.gcube.smartgears.managers.ContainerManager; -import org.junit.After; -import org.junit.Ignore; -import org.junit.Test; - -import app.SomeApp; - -public class ContainerLifecycleTest { - - SomeApp app = new SomeApp(); - - @After - public void teardown() { - app.stop(); - } - - @Test - public void containerGoesToPartActiveWhenAppFails() { - - - ApplicationContext actx = app.start(); - - ContainerContext ctx = actx.container(); - - assertEquals(ContainerState.active,ctx.lifecycle().state()); - - actx.lifecycle().moveTo(ApplicationState.failed); - - assertEquals(ContainerState.partActive,ctx.lifecycle().state()); - } - - @Test - public void containerGoesToPartActiveWhenAppStops() { - - ApplicationContext actx = app.start(); - - ContainerContext ctx = actx.container(); - - assertEquals(ContainerState.active,ctx.lifecycle().state()); - - actx.lifecycle().moveTo(ApplicationState.stopped); - - assertEquals(ContainerState.partActive,ctx.lifecycle().state()); - } - - - //used interactively to study shutdown - @Ignore - @Test - public void containerShutsdown() throws Exception { - - ApplicationContext actx = app.start(); - - ContainerContext ctx = actx.container(); - - assertEquals(ContainerState.active,ctx.lifecycle().state()); - - ContainerManager.instance.stop(true); - app.stop(); - - Thread.sleep(10000); - } -} diff --git a/src/test/java/test/container/ProfileManagementTest.java b/src/test/java/test/container/ProfileManagementTest.java deleted file mode 100644 index 1b45685..0000000 --- a/src/test/java/test/container/ProfileManagementTest.java +++ /dev/null @@ -1,98 +0,0 @@ -package test.container; - -import static junit.framework.Assert.*; -import static org.gcube.smartgears.Constants.*; -import static org.gcube.smartgears.lifecycle.container.ContainerState.*; - -import java.io.File; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; - -import org.gcube.common.events.Observes; -import org.gcube.common.resources.gcore.HostingNode; -import org.gcube.common.resources.gcore.Resources; -import org.gcube.smartgears.context.application.ApplicationContext; -import org.gcube.smartgears.context.container.ContainerContext; -import org.junit.Test; - -import app.SomeApp; - -public class ProfileManagementTest { - - @Test - public void createsStoresAndPublishesAValidProfile() throws Exception { - - ContainerContext ctx = startAppAndGetContainerContext(); - - HostingNode node = ctx.profile(HostingNode.class); - - assertNotNull(node); - - //assert profile has been created - File profile = ctx.configuration().persistence().file(container_profile_file_path); - assertTrue(profile.exists()); - - assertFalse(node.scopes().isEmpty()); - - Resources.validate(node); - - } - - @Test - public void loadsAndUpdatesProfile() throws Exception { - - startAppAndGetContainerContext(); - - SomeApp runtwice = new SomeApp(); - - runtwice.dirtyRun(); - - ContainerContext ctx = runtwice.start().container(); - - assertNotNull(ctx.profile(HostingNode.class)); - - HostingNode node = ctx.profile(HostingNode.class); - - Resources.validate(node); - } - - - @Test - public void periodicallyUpdatesAndPublishesProfile() throws Exception { - - SomeApp app = new SomeApp(); - - app.containerConfiguration().publicationFrequency(1); - - ContainerContext ctx = app.start().container(); - - final CountDownLatch latch = new CountDownLatch(1); - - assertEquals(active,ctx.lifecycle().state()); - - ctx.events().subscribe(new Object() { - - @Observes - void profileHasChangedAfterPeriodicUpdate(HostingNode ignore) { - latch.countDown(); - } - - }); - - if (!latch.await(4,TimeUnit.SECONDS)) - fail(); - - ctx.lifecycle().moveTo(stopped); //should stop periodic updates - - } - - - ContainerContext startAppAndGetContainerContext() { - - SomeApp app = new SomeApp(); - - ApplicationContext appCtx = app.start(); - - return appCtx.container(); - } -} diff --git a/src/test/java/test/container/StartupTest.java b/src/test/java/test/container/StartupTest.java deleted file mode 100644 index cbb5a0a..0000000 --- a/src/test/java/test/container/StartupTest.java +++ /dev/null @@ -1,65 +0,0 @@ -package test.container; - -import static org.gcube.smartgears.Constants.*; -import static org.gcube.smartgears.lifecycle.container.ContainerState.*; -import static org.junit.Assert.*; - -import org.gcube.smartgears.context.application.ApplicationContext; -import org.junit.After; -import org.junit.Test; - -import app.SomeApp; - -public class StartupTest { - - SomeApp app = new SomeApp(); - - @After - public void teardown() { - app.stop(); - } - - @Test(expected=RuntimeException.class) - public void failsIfHomeIsNotConfigured() { - - System.clearProperty(ghn_home_property); - - app.start(); - - assertFalse(app.isActive()); - } - - @Test(expected=RuntimeException.class) - public void failsIfInstallationFolderIsInvalid() { - - System.setProperty(ghn_home_property,"foo"); - - app.start(); - - assertFalse(app.isActive()); - - } - - @Test(expected=RuntimeException.class) - public void failsIfConfigurationIsInvalid() { - - app.containerConfiguration().hostname(null); - - app.start(); - - assertFalse(app.isActive()); - - } - - @Test - public void leavesContainerToActive() { - - ApplicationContext ctx = app.start(); - - assertEquals(active,ctx.container().lifecycle().state()); - - assertTrue(app.isActive()); - } - - -} diff --git a/src/test/java/utils/ConfigurationTest.java b/src/test/java/utils/ConfigurationTest.java new file mode 100644 index 0000000..9948a84 --- /dev/null +++ b/src/test/java/utils/ConfigurationTest.java @@ -0,0 +1,88 @@ +package utils; + +import java.io.InputStream; +import java.util.List; + +import org.gcube.com.fasterxml.jackson.databind.ObjectMapper; +import org.gcube.smartgears.configuration.PersistenceConfiguration; +import org.gcube.smartgears.configuration.application.ApplicationConfiguration; +import org.gcube.smartgears.configuration.application.GCubeExclude; +import org.gcube.smartgears.persistence.LocalWriter; +import org.gcube.smartgears.persistence.LocalWriterConfiguration; +import org.junit.Test; +import org.yaml.snakeyaml.Yaml; + +import junit.framework.Assert; + +public class ConfigurationTest { + + static final String yamlConf = "name: test\n" + + "group: group\n" + + "version: 1.0.0\n" + + "description: pippo\n" + + "proxable: true\n" + + "excludes:\n" + + "- path: /pippo/*\n" + + "- handlers: [H1, H2]\n" + + " path: /trip\n" + + "persistence:\n" + + " implementationClass: org.gcube.smartgears.persistence.LocalWriter\n" + + " writerConfiguration:\n" + + " className: org.gcube.smartgears.persistence.LocalWriterConfiguration\n" + + " location: /tmp"; + + static final String yamlConfBase = "name: test\n" + + "group: group\n" + + "version: 1.0.0\n" + + "description: pippo"; + + @Test + public void deserialize() { + Yaml yaml = new Yaml(); + InputStream inputStream = this.getClass() + .getClassLoader() + .getResourceAsStream("applicationTest.yaml"); + yaml.load(inputStream); + + } + + @Test + public void serialize() throws Exception{ + ApplicationConfiguration configuration =new ApplicationConfiguration(); + configuration.name("test").group("group").description("pippo").version("1.0.0").excludes(new GCubeExclude("/pippo/*"), new GCubeExclude(List.of("H1","H2"), "/trip")); + configuration.persistenceConfiguration(new PersistenceConfiguration(LocalWriter.class, new LocalWriterConfiguration("/tmp"))); + /* + ObjectMapper mapper = new ObjectMapper(); + String value = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(configuration); + System.out.println(value); + Map res = mapper.readValue(value, Map.class); + + + + Yaml yaml = new Yaml(); + String yamlValue = yaml.dump(res); + System.out.println(yamlValue); + */ + + Yaml yaml = new Yaml(); + ObjectMapper mapper = new ObjectMapper(); + String mapAsString = mapper.writeValueAsString(yaml.load(yamlConf)); + System.out.println(mapAsString); + + ApplicationConfiguration conf2 = mapper.readValue(mapAsString, ApplicationConfiguration.class); + Assert.assertTrue(configuration.equals(conf2)); + } + + @Test + public void serializeBase() throws Exception{ + ObjectMapper mapper = new ObjectMapper(); + Yaml yaml = new Yaml(); + + String mapAsString = mapper.writeValueAsString(yaml.load(yamlConfBase)); + System.out.println(mapAsString); + + ApplicationConfiguration conf2 = mapper.readValue(mapAsString, ApplicationConfiguration.class); + Assert.assertEquals("test", conf2.name()); + + } +} diff --git a/src/test/java/utils/PersistenceWriterTest.java b/src/test/java/utils/PersistenceWriterTest.java new file mode 100644 index 0000000..23abf16 --- /dev/null +++ b/src/test/java/utils/PersistenceWriterTest.java @@ -0,0 +1,43 @@ +package utils; + +import java.io.File; + +import org.gcube.common.validator.annotations.IsValid; +import org.gcube.common.validator.annotations.NotNull; +import org.gcube.smartgears.configuration.ComponentConfiguration; +import org.gcube.smartgears.persistence.PersistenceWriter; + +public class PersistenceWriterTest implements PersistenceWriter{ + + @IsValid @NotNull + String location; + + @Override + public File file(String path) { + return new File(location+"/"+path); + } + + @Override + public File writefile(String path) { + return new File(location+"/"+path); + } + + public String getLocation() { + return location; + } + + public void setLocation(String location) { + this.location = location; + } + + @Override + public long getFreeSpace() { + return 0; + } + + @Override + public void configure(ComponentConfiguration configuration) { + + } + +} diff --git a/src/test/java/utils/TestProvider.java b/src/test/java/utils/TestProvider.java index 1d7a295..6d27894 100644 --- a/src/test/java/utils/TestProvider.java +++ b/src/test/java/utils/TestProvider.java @@ -1,26 +1,28 @@ package utils; +import java.io.File; +import java.util.List; + import javax.servlet.ServletContext; -import org.gcube.informationsystem.publisher.ScopedPublisher; import org.gcube.smartgears.configuration.application.ApplicationConfiguration; -import org.gcube.smartgears.configuration.application.ApplicationExtensions; import org.gcube.smartgears.configuration.application.ApplicationHandlers; import org.gcube.smartgears.context.application.ApplicationContext; import org.gcube.smartgears.context.container.ContainerContext; +import org.gcube.smartgears.extensions.ApplicationExtension; import org.gcube.smartgears.provider.DefaultProvider; public class TestProvider extends DefaultProvider { + public TestProvider(File configFile) { + super(configFile); + } + public ApplicationContext context; public ApplicationConfiguration configuration; public ApplicationHandlers handlers; - public ApplicationExtensions extensions; - public ScopedPublisher publisher; + public List extensions; - public void use(ScopedPublisher publisher) { - this.publisher=publisher; - } public void use(ApplicationConfiguration configuration) { this.configuration=configuration; @@ -30,15 +32,20 @@ public class TestProvider extends DefaultProvider { this.handlers=handlers; } - public void use(ApplicationExtensions extensions) { + public void use(List extensions) { this.extensions=extensions; } - @Override - public ScopedPublisher publisherFor(ApplicationContext context) { - return publisher==null?super.publisherFor(context):publisher; - } + /* + @Override + public SmartGearsConfiguration smartgearsConfiguration() { + SmartGearsConfiguration conf = new SmartGearsConfiguration(); + conf.version("0.0.1-TEST"); + return conf ; + }*/ + + @Override public ApplicationContext contextFor(ContainerContext container,ServletContext application) { return context = super.contextFor(container,application); @@ -50,7 +57,7 @@ public class TestProvider extends DefaultProvider { } @Override - public ApplicationExtensions extensionsFor(ApplicationContext context) { + public List extensionsFor(ApplicationContext context) { return extensions==null?super.extensionsFor(context):extensions; } } diff --git a/src/test/java/utils/TestUtils.java b/src/test/java/utils/TestUtils.java deleted file mode 100644 index 61ebc8e..0000000 --- a/src/test/java/utils/TestUtils.java +++ /dev/null @@ -1,185 +0,0 @@ -package utils; - -import java.io.File; -import java.io.FileWriter; -import java.io.StringWriter; -import java.util.ArrayList; -import java.util.List; - -import javax.xml.bind.JAXBContext; -import javax.xml.bind.JAXBException; - -import org.gcube.smartgears.configuration.application.ApplicationConfiguration; -import org.gcube.smartgears.configuration.application.ApplicationExtensions; -import org.gcube.smartgears.configuration.application.ApplicationHandlers; -import org.gcube.smartgears.configuration.application.DefaultApplicationConfiguration; -import org.gcube.smartgears.configuration.container.ContainerConfiguration; -import org.gcube.smartgears.extensions.ApplicationExtension; -import org.gcube.smartgears.handlers.application.ApplicationHandler; - - -public class TestUtils { - - - public static String location = "target/ghn-home"; - public static String context_root = "test-app"; - public static String context_root_path = "/" + context_root; - public static String servlet_name = "test"; - public static String scope = "/gcube/devsec"; - - public static class Box { - - T t; - - public void put(T t) { - this.t=t; - } - - public T get() { - return t; - } - - } - - /** - * Serialises a {@link ContainerConfiguration} to XML in a file. - * - * @param config the configuration - * @param the file - * @return the serialisation - * @throws RuntimeException if the configuration cannot be serialised - */ - public static void serialise(ContainerConfiguration config, File file) { - - //serialises configuration - - try { - JAXBContext ctx = JAXBContext.newInstance(ContainerConfiguration.class); - - FileWriter writer = new FileWriter(file); - - ctx.createMarshaller().marshal(config, writer); - - writer.flush(); - writer.close(); - - } catch (Exception e) { - - throw new RuntimeException("invalid service configuration", e); - } - - } - /** - * Serialises a {@link ApplicationConfiguration} to XML. - * - * @param config the configuration - * @return the serialisation - * @throws RuntimeException if the configuration cannot be serialised - */ - public static String bind(ApplicationConfiguration config) { - - try { - - //collect handler classes - List> classes = new ArrayList>(); - - classes.add(DefaultApplicationConfiguration.class); - if (config.persistence()!=null) - classes.add(config.persistence().getClass()); - - //serialises configuration - - JAXBContext ctx = JAXBContext.newInstance(classes.toArray(new Class[0])); - - StringWriter writer = new StringWriter(); - - ctx.createMarshaller().marshal(config, writer); - - return writer.toString(); - - - } catch (JAXBException e) { - - throw new RuntimeException("invalid application configuration", e); - - } - } - - /** - * Serialises application handlers. - * - * @param handlers the handlers - * @return the serialisation - * @throws RuntimeException if the handlers cannot be serialised - */ - public static String bind(ApplicationHandlers handlers) { - - try { - - //collect handler classes - List> classes = new ArrayList>(); - - classes.add(ApplicationHandlers.class); - - for (ApplicationHandler h : handlers.lifecycleHandlers()) - classes.add(h.getClass()); - - for (ApplicationHandler h : handlers.requestHandlers()) - classes.add(h.getClass()); - - - //serialises configuration - - JAXBContext ctx = JAXBContext.newInstance(classes.toArray(new Class[0])); - - StringWriter writer = new StringWriter(); - - ctx.createMarshaller().marshal(handlers, writer); - - return writer.toString(); - - } catch (JAXBException e) { - - throw new RuntimeException("invalid handler configuration", e); - - } - } - - /** - * Serialises application extensions. - * - * @param extensions the extensions - * @return the serialisation - * @throws RuntimeException if the extensions cannot be serialised - */ - public static String bind(ApplicationExtensions extensions) { - - try { - - //collect handler classes - List> classes = new ArrayList>(); - - classes.add(ApplicationExtensions.class); - - for (ApplicationExtension h : extensions.extensions()) - classes.add(h.getClass()); - - - //serialises configuration - - JAXBContext ctx = JAXBContext.newInstance(classes.toArray(new Class[0])); - - StringWriter writer = new StringWriter(); - - ctx.createMarshaller().marshal(extensions, writer); - - return writer.toString(); - - } catch (JAXBException e) { - - throw new RuntimeException("invalid handler configuration", e); - - } - } - -} diff --git a/src/test/resources/application.yaml b/src/test/resources/application.yaml new file mode 100644 index 0000000..c684c27 --- /dev/null +++ b/src/test/resources/application.yaml @@ -0,0 +1,18 @@ +name: test +group: group +version: 1.0.0 +#not mandatory +description: pippo +#not mandatory +proxable: true +#not mandatory +excludes: + - path: /pippo/* + - handlers: [H1, H2] + path: /trip +#not mandatory +persistence: + implementationClass: org.gcube.smartgears.persistence.LocalWriter + writerConfiguration: + className: org.gcube.smartgears.persistence.LocalWriterConfiguration + location: /tmp \ No newline at end of file diff --git a/src/test/resources/container.ini b/src/test/resources/container.ini new file mode 100644 index 0000000..8319c5c --- /dev/null +++ b/src/test/resources/container.ini @@ -0,0 +1,41 @@ +[node] +; mandatory +; optional fields: mode (=online), publication-frequency-seconds (=60), authorizeChildrenContext (=false) +mode = online +hostname = dlib29.isti.cnr.it +protocol= http +port = 8080 +infrastructure = gcube +authorizeChildrenContext = true +publicationFrequencyInSeconds = 60 + +[properties] +; not mandatory +SmartGearsDistribution = 1.0.0 +SmartGearsDistributionBundle = UnBundled + +[site] +; mandatory +country = it +location = rome + +;[proxy] +; not mandatory +;protocol = https +;hostname = proxy +;port = 80 + + +[authorization] +; mandatory +; optional fields: provider factory (=org.gcube.smartgears.security.defaults.DefaultAuthorizationProviderFactory) +factory = org.gcube.smartgears.security.defaults.DefaultAuthorizationProviderFactory +factory.endpoint = https://accounts.dev.d4science.org/auth/realms/d4science/protocol/openid-connect/token +credentials.class = org.gcube.smartgears.security.SimpleCredentials +credentials.clientID = testClient +credentials.secret = testSecret + +;[persistence] +; not mandatory (default is LocalPersistence writing in the ghn home) +;class = utils.PersistenceWriterTest +;location = /tmp