Merge remote-tracking branch 'origin/smartgears4'
commit
725b19c168
@ -1,3 +1,4 @@
|
||||
/target/
|
||||
/.classpath
|
||||
/bin/
|
||||
/bin/
|
||||
|
@ -1,2 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<smartgears version="${project.version}" />
|
@ -0,0 +1,2 @@
|
||||
[smartgears]
|
||||
version = ${version}
|
@ -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() + "]";
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -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 {
|
||||
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
package org.gcube.smartgears.configuration;
|
||||
|
||||
public interface Configurable {
|
||||
|
||||
void configure(ComponentConfiguration configuration);
|
||||
}
|
@ -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<? extends ComponentConfiguration> value();
|
||||
}
|
@ -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<? extends PersistenceWriter> implementationClass;
|
||||
|
||||
@IsValid
|
||||
private ComponentConfiguration writerConfiguration;
|
||||
|
||||
protected PersistenceConfiguration() {}
|
||||
|
||||
public <T extends ComponentConfiguration> PersistenceConfiguration(Class<? extends PersistenceWriter> implementationClass, T writerConfiguration) {
|
||||
super();
|
||||
this.implementationClass = implementationClass;
|
||||
this.writerConfiguration = writerConfiguration;
|
||||
}
|
||||
|
||||
public Class<? extends PersistenceWriter> getImplementationClass() {
|
||||
return this.implementationClass;
|
||||
}
|
||||
|
||||
public ComponentConfiguration getWriterConfiguration() {
|
||||
return writerConfiguration;
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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.
|
||||
* <p>
|
||||
* 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 {
|
||||
|
||||
|
||||
/**
|
||||
* Returns the management mode of the application.
|
||||
* @return the management mode
|
||||
*/
|
||||
Mode mode();
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
/**
|
||||
* Returns the class of the application
|
||||
* @return the class
|
||||
*/
|
||||
String serviceClass();
|
||||
|
||||
/**
|
||||
* Sets the class of the application.
|
||||
* @param serviceClass the class
|
||||
* @return this configuration
|
||||
*/
|
||||
ApplicationConfiguration serviceClass(String serviceClass);
|
||||
|
||||
/**
|
||||
* 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);
|
||||
@NotNull
|
||||
String name;
|
||||
|
||||
/**
|
||||
* Returns the description of the application.
|
||||
* @return the description
|
||||
*/
|
||||
String description();
|
||||
@NotNull
|
||||
String group;
|
||||
|
||||
/**
|
||||
* 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<String> startTokens();
|
||||
|
||||
/**
|
||||
* Sets the tokens in which the application operates when it first starts.
|
||||
* @param scopes the scopes
|
||||
* @return this configuration
|
||||
*/
|
||||
ApplicationConfiguration startTokens(Set<String> tokens);
|
||||
|
||||
|
||||
/**
|
||||
* Returns the persistence manager of the application.
|
||||
* @return the manager
|
||||
*/
|
||||
Persistence persistence();
|
||||
|
||||
@NotNull
|
||||
String version;
|
||||
|
||||
String description="";
|
||||
|
||||
@JsonIgnore
|
||||
String context;
|
||||
|
||||
private boolean proxable = true;
|
||||
|
||||
Set<GCubeExclude> excludes= new HashSet<>();
|
||||
|
||||
Set<GCubeInclude> includes= new HashSet<>();
|
||||
|
||||
@NotEmpty @JsonProperty("persistence")
|
||||
PersistenceConfiguration persistenceConfiguration;
|
||||
|
||||
public Set<GCubeExclude> excludes() {
|
||||
return excludes;
|
||||
}
|
||||
|
||||
public Set<GCubeInclude> includes() {
|
||||
return includes;
|
||||
}
|
||||
|
||||
public ApplicationConfiguration() {}
|
||||
|
||||
public String name() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public String context() {
|
||||
return context;
|
||||
}
|
||||
|
||||
public ApplicationConfiguration excludes(GCubeExclude ... excludes) {
|
||||
this.excludes=new HashSet<GCubeExclude>(Arrays.asList(excludes));
|
||||
return this;
|
||||
}
|
||||
|
||||
public ApplicationConfiguration includes(GCubeInclude... includes) {
|
||||
this.includes=new HashSet<GCubeInclude>(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;
|
||||
}
|
||||
|
||||
|
||||
public String description() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public ApplicationConfiguration description(String description) {
|
||||
this.description=description;
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean proxable() {
|
||||
return proxable;
|
||||
}
|
||||
|
||||
public PersistenceConfiguration persistenceConfiguration() {
|
||||
return persistenceConfiguration;
|
||||
}
|
||||
|
||||
public void validate() {
|
||||
|
||||
List<String> msgs = new ArrayList<String>();
|
||||
|
||||
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 int hashCode() {
|
||||
return Objects.hash(description, excludes, group, includes, name, proxable, version);
|
||||
}
|
||||
|
||||
@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 a set of request paths that should not be subjected to request management.
|
||||
* @return the set of exclude paths.
|
||||
*/
|
||||
Set<Exclude> excludes();
|
||||
|
||||
/**
|
||||
* Returns a set of request paths that should be subjected to request management.
|
||||
* @return the set of exclude paths.
|
||||
*/
|
||||
Set<Include> 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);
|
||||
|
||||
|
||||
|
||||
}
|
@ -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<ApplicationExtension> extensions = new ArrayList<ApplicationExtension>();
|
||||
|
||||
public ApplicationExtensions() {}
|
||||
|
||||
/**
|
||||
* Returns the extensions for the application.
|
||||
* @return the extensions
|
||||
*/
|
||||
public List<ApplicationExtension> 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<String> msgs = new ArrayList<String>();
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
}
|
@ -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<Exclude> excludes() {
|
||||
return application.excludes();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Include> includes() {
|
||||
return application.includes();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void merge(ApplicationConfiguration config) {
|
||||
application.merge(config);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Set<String> startTokens() {
|
||||
return application.startTokens();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ApplicationConfiguration startTokens(Set<String> 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);
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -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.
|
||||
* <p>
|
||||
* 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<String> tokens = new HashSet<String>();
|
||||
|
||||
@XmlElement(name="description")
|
||||
String description="";
|
||||
|
||||
@XmlElementRef
|
||||
@IsValid
|
||||
ProxyAddress proxyAddress;
|
||||
|
||||
@XmlElementRef
|
||||
Set<Exclude> excludes= new LinkedHashSet<Exclude>();
|
||||
|
||||
@XmlElementRef
|
||||
Set<Include> includes= new LinkedHashSet<Include>();
|
||||
|
||||
@XmlElementRef(type=DefaultPersistence.class)
|
||||
@NotNull @IsValid
|
||||
private Persistence persistenceManager;
|
||||
|
||||
@Override
|
||||
public Set<Exclude> excludes() {
|
||||
return excludes;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Set<Include> 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<Exclude>(Arrays.asList(excludes));
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ApplicationConfiguration includes(Include... includes) {
|
||||
this.includes=new HashSet<Include>(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<String> startTokens() {
|
||||
return tokens;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ApplicationConfiguration startTokens(Set<String> 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<String> msgs = new ArrayList<String>();
|
||||
|
||||
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());
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
@ -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
|
||||
+ "]";
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
@ -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<ContainerHandler> handlers = new ArrayList<ContainerHandler>();
|
||||
|
||||
public ContainerHandlers() {}
|
||||
|
||||
/**
|
||||
* Returns the {@link ContainerHandler}s for the service.
|
||||
* @return the lifecycle handlers
|
||||
*/
|
||||
public List<ContainerHandler> 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<ContainerHandler> handlers = other.get();
|
||||
for (ContainerHandler handler : handlers)
|
||||
if (!this.get().contains(handler))
|
||||
this.get().add(handler);
|
||||
}
|
||||
}
|
@ -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<String> msgs = new ArrayList<String>();
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -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<Class<?>> 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();
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -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());
|
||||
}
|
||||
|
||||
}
|
@ -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<String> 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));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -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.
|
||||
* <p>
|
||||
*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<String> 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<String> retainedContexts = new ArrayList<String>(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<String> 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<String> resolveScopesFromTokens(Collection<String> tokens){
|
||||
List<String> scopes = new ArrayList<String>(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;
|
||||
}
|
||||
|
||||
}
|
@ -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());
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
@ -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<Long> startCallThreadLocal = new ThreadLocal<Long>();
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
@ -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.
|
||||
* <p>
|
||||
*
|
||||
* The manager:
|
||||
*
|
||||
* <ul>
|
||||
* <li>creates the profile when the application starts for the first time;
|
||||
* <li>loads the profile when the application restarts;
|
||||
* <li>publishes the profile when the application becomes active, and at any
|
||||
* lifecycle change thereafter;
|
||||
* <li>stores the profile locally after each publication;
|
||||
* </ul>
|
||||
*
|
||||
* @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<Publisher> 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;
|
||||
}
|
||||
}
|
||||
|
@ -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<HashMap<String, String>> info = cpuInfo();
|
||||
|
||||
Group<Processor> processors = node.profile().description().processors();
|
||||
|
||||
for (HashMap<String, String> 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<HashMap<String, String>> cpuInfo() {
|
||||
|
||||
ArrayList<HashMap<String, String>> map = new ArrayList<HashMap<String, String>>();
|
||||
|
||||
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<String, String> 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<String, String>();
|
||||
}
|
||||
|
||||
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<String, Long> 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<String, Double> 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<Variable> variables = node.profile().description().environmentVariables();
|
||||
|
||||
// Cleaning variables to avoid duplicates
|
||||
variables.removeAll(node.profile().description().environmentVariables());
|
||||
|
||||
Map<String, String> map = new HashMap<String, String>();
|
||||
map.putAll(cfg.properties());
|
||||
map.putAll(System.getenv());
|
||||
|
||||
for (Map.Entry<String, String> 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<String, String> envvars = new HashMap<String, String>();
|
||||
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<String,String> 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<String, Double> loadStatistics() {
|
||||
|
||||
Map<String, Double> result = new HashMap<String, Double>();
|
||||
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<String, Long> memoryUsage() {
|
||||
Map<String, Long> map = new HashMap<String, Long>();
|
||||
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];
|
||||
}
|
||||
}
|
@ -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.
|
||||
* <p>
|
||||
*
|
||||
* The manager:
|
||||
*
|
||||
* <ul>
|
||||
* <li>creates the profile when the container starts for the first time;
|
||||
* <li>loads the profile when the container restarts;
|
||||
* <li>publishes the profile when the container becomes active, and at any lifecycle change thereafter;
|
||||
* <li>stores the profile locally after each publication;
|
||||
* </ul>
|
||||
*
|
||||
* @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;
|
||||
}
|
||||
}
|
@ -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.
|
||||
* <p>
|
||||
* 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<String> 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<String> retainedContexts = new ArrayList<String>(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<String> 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<String> 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<String> resolveScopesFromTokens(Collection<String> tokens){
|
||||
List<String> scopes = new ArrayList<String>(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;
|
||||
}
|
||||
}
|
@ -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<HealthCheck> checks = new LinkedList<>();
|
||||
|
||||
public void register(HealthCheck check){
|
||||
checks.add(check);
|
||||
}
|
||||
|
||||
public List<HealthCheck> getChecks() {
|
||||
return checks;
|
||||
}
|
||||
}
|
@ -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<HealthCheckResponse> checks;
|
||||
|
||||
|
||||
|
||||
public HealthResponse(Status status, List<HealthCheckResponse> checks) {
|
||||
super();
|
||||
this.status = status;
|
||||
this.checks = checks;
|
||||
}
|
||||
|
||||
public Status getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public List<HealthCheckResponse> getChecks() {
|
||||
return checks;
|
||||
}
|
||||
|
||||
}
|
@ -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<HealthCheck> checks = healthManager.getChecks();
|
||||
|
||||
List<HealthCheckResponse> 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();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -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<String> 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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -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);
|
||||
|
||||
}
|
@ -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();
|
||||
|
||||
}
|
@ -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.
|
||||
* <p>
|
||||
* Used for applications and or containers that operate in {@link Mode#offline}.
|
||||
*
|
||||
* @author Fabio Simeoni
|
||||
*
|
||||
*/
|
||||
public class OfflinePublisher implements ScopedPublisher {
|
||||
|
||||
@Override
|
||||
public <T extends Resource> T update(T resource){
|
||||
// do nothing
|
||||
return resource;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends Resource> T create(T resource, List<String> 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 extends Resource> T remove(T resource, List<String> 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;
|
||||
}
|
||||
|
||||
}
|
@ -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<String> 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<String> 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<String> 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<String> contexts);
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
package org.gcube.smartgears.publishing;
|
||||
|
||||
public @interface SmartgearsProfilePublisher {
|
||||
|
||||
}
|
@ -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<String> getContexts();
|
||||
|
||||
Secret getSecretForContext(String context);
|
||||
|
||||
Credentials getCredentials();
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
package org.gcube.smartgears.security;
|
||||
|
||||
import org.gcube.common.security.credentials.Credentials;
|
||||
|
||||
public interface AuthorizationProviderFactory<T extends AuthorizationProvider> {
|
||||
|
||||
T connect(Credentials credentials);
|
||||
|
||||
}
|
@ -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 + "]";
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -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<String> getContexts() {
|
||||
Set<String> contexts = new HashSet<String>();
|
||||
try {
|
||||
TokenResponse response = client.queryOIDCToken(new URL(this.endpoint), credentials.getClientID(), credentials.getSecret());
|
||||
Map<String, Access> 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;
|
||||
}
|
||||
}
|
@ -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<DefaultAuthorizationProvider>{
|
||||
|
||||
@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;
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
@ -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<String> MINIMAL_ROLES = Arrays.asList("Member");
|
||||
|
||||
@JsonProperty("aud")
|
||||
private String context;
|
||||
|
||||
@JsonProperty("resource_access")
|
||||
private Map<String, Roles> 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<String> 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<String> roles = new ArrayList<>();
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -1,5 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<handlers>
|
||||
<accounting-management />
|
||||
<profile-management />
|
||||
</handlers>
|
@ -1,4 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<extensions>
|
||||
<remote-management/>
|
||||
</extensions>
|
@ -1,11 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<handlers>
|
||||
<lifecycle>
|
||||
<profile-management />
|
||||
</lifecycle>
|
||||
<request>
|
||||
<context-retriever />
|
||||
<request-validation />
|
||||
<request-accounting />
|
||||
</request>
|
||||
</handlers>
|
@ -1 +0,0 @@
|
||||
org.gcube.smartgears.extensions.resource.RemoteResource
|
@ -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
|
@ -1,2 +0,0 @@
|
||||
org.gcube.smartgears.handlers.container.lifecycle.ProfileManager
|
||||
org.gcube.smartgears.handlers.container.lifecycle.AccountingManager
|
@ -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<String>()),"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<String,List<Object>> 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;
|
||||
}
|
||||
|
||||
}
|
@ -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.
|
||||
* <p>
|
||||
* <ul>
|
||||
* <li>uses a default configuration that can be customised (cf. {@link #configuration()});
|
||||
* <li>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()};
|
||||
* <li>can be started to have a default behaviour when called, ({@link #start()}) or else a custom behaviour (
|
||||
* {@link #startWith(Runnable)};
|
||||
* </ul>
|
||||
* 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.
|
||||
* <p>
|
||||
* Use only within a single test!
|
||||
*/
|
||||
public void dirtyRun() {
|
||||
this.clean = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the configuration of the application.
|
||||
* <p>
|
||||
* 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.
|
||||
* <p>
|
||||
* 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.
|
||||
* <p>
|
||||
* 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.
|
||||
* <p>
|
||||
* 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 <code>true</code> if the application was successfully start in the container.
|
||||
*
|
||||
* @return <code>true</code> 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();
|
||||
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
@ -1,15 +0,0 @@
|
||||
<web-app>
|
||||
|
||||
<display-name>test-app</display-name>
|
||||
|
||||
<servlet>
|
||||
<servlet-name>test</servlet-name>
|
||||
<servlet-class>app.TestServlet</servlet-class>
|
||||
</servlet>
|
||||
|
||||
<servlet-mapping>
|
||||
<servlet-name>test</servlet-name>
|
||||
<url-pattern>/*</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
</web-app>
|
@ -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());
|
||||
}
|
||||
}
|
@ -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 = "<smartgears version='1.0.0-SNAPSHOT'/>";
|
||||
|
||||
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");
|
||||
|
||||
}
|
||||
}
|
@ -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());
|
||||
}
|
||||
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue