Compare commits
89 Commits
Author | SHA1 | Date |
---|---|---|
lucio | 8c4ffc9b28 | |
lucio | 855820b2fa | |
lucio | a9535591ab | |
lucio | d2aaf739ee | |
lucio | c5c57f5b34 | |
lucio | 4db089d043 | |
lucio | f4ae6f1fd6 | |
lucio | 7f446b680c | |
lucio | 05dd9f2482 | |
lucio | 48347ea8f7 | |
lucio | 51fbda1161 | |
lucio | bb55ce6f44 | |
lucio | 1fbd524fc4 | |
lucio | 82c155e3a4 | |
lucio | 3aeca7c089 | |
lucio | e36605ec12 | |
lucio | 5c80342e8c | |
lucio | a34e349c3b | |
lucio | 36a685733d | |
lucio | 64fb289c40 | |
Roberto Cirillo | b1b8e0df2e | |
Roberto Cirillo | aa58b66d79 | |
lucio | 6454f71672 | |
lucio | 409499956a | |
lucio | bfce9d076d | |
lucio | b4faa4e2c5 | |
lucio | 4d060fbb54 | |
lucio | e193c80d11 | |
lucio | 6dec0d7a6a | |
lucio | 57d25b3ed3 | |
lucio | 5a771aeeb5 | |
lucio | 101b0f1e0d | |
lucio | a7f666556d | |
lucio | c00d389357 | |
lucio | 873081893e | |
Lucio Lelii | 725b19c168 | |
lucio | be3d37d6c3 | |
lucio | 766238c8e3 | |
lucio | e48f50e91b | |
lucio | a76b823c49 | |
lucio | b9f17e5a0b | |
lucio | b873f97187 | |
lucio | 98c41e7463 | |
Lucio Lelii | 3407ce025c | |
Lucio Lelii | 29e02ac587 | |
Lucio Lelii | d12e4a33b2 | |
Lucio Lelii | de2c95f134 | |
Lucio Lelii | e7aabc3fb8 | |
Luca Frosini | 1cf09963a2 | |
Lucio Lelii | 36e56d1e7d | |
Luca Frosini | d024c129d5 | |
Lucio Lelii | b5f6959da4 | |
Roberto Cirillo | f01ee71e32 | |
Luca Frosini | 952703c780 | |
Lucio Lelii | c92f119a0c | |
Lucio Lelii | 551740212f | |
Lucio Lelii | b73a2963e5 | |
Lucio Lelii | 08838cb6d6 | |
Lucio Lelii | 2fe7d3d4bc | |
Lucio Lelii | 4b75535a9d | |
Lucio Lelii | e5c0b8a23d | |
Lucio Lelii | b9e2298ca9 | |
Lucio Lelii | 7e00459e9a | |
Lucio Lelii | 1b79f8e813 | |
Lucio Lelii | 58bb6a28e4 | |
Lucio Lelii | 710e8ef242 | |
Lucio Lelii | 08781a5f3a | |
Lucio Lelii | 6f999bcedc | |
Lucio Lelii | 80f5de688a | |
Lucio Lelii | 8030b049d0 | |
Lucio Lelii | 961676484f | |
Lucio Lelii | 4b619414a7 | |
Lucio Lelii | 64bef37271 | |
Lucio Lelii | 230ae3bde9 | |
Lucio Lelii | f54efc1e4e | |
Lucio Lelii | a285c20b38 | |
Lucio Lelii | f6e49975d0 | |
Lucio Lelii | 9947bfbc7d | |
Lucio Lelii | 454533abcd | |
Lucio Lelii | 08b3cd590a | |
Lucio Lelii | cf3c134953 | |
Luca Frosini | 515891e083 | |
Luca Frosini | 635036bce1 | |
Luca Frosini | baab05f015 | |
Luca Frosini | b46715dc05 | |
Luca Frosini | 405a65282d | |
Luca Frosini | b703d6605b | |
Luca Frosini | 29ac4def10 | |
Luca Frosini | 9239e13120 |
|
@ -1,3 +1,4 @@
|
||||||
/target/
|
/target/
|
||||||
/.classpath
|
/.classpath
|
||||||
/bin/
|
/bin/
|
||||||
|
/bin/
|
||||||
|
|
13
CHANGELOG.md
13
CHANGELOG.md
|
@ -2,13 +2,18 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
|
||||||
|
|
||||||
# Changelog for Common Smartgears
|
# Changelog for Common Smartgears
|
||||||
|
|
||||||
## [v3.1.5] - 2022-04-20
|
## [v4.0.0]
|
||||||
|
|
||||||
- Added roles to ExternalService Info on request handler verification
|
- support ticket #28304
|
||||||
|
- porting to keycloak
|
||||||
|
- moved to jakarta and servlet6
|
||||||
|
- added token expiration
|
||||||
|
|
||||||
## [v3.1.4] - 2022-03-29
|
|
||||||
|
|
||||||
- fixes issue [#23075]
|
## [v3.2.0] - 2023-04-12
|
||||||
|
|
||||||
|
- Added SecretManagerProvider thread local from authorization-utils [#22871]
|
||||||
|
- Added Linux distribution version [#22933]
|
||||||
|
|
||||||
## [v3.1.3] - 2022-03-21
|
## [v3.1.3] - 2022-03-21
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
# Acknowledgments
|
||||||
|
|
||||||
|
The projects leading to this software have received funding from a series of European Union programmes including:
|
||||||
|
|
||||||
|
- the Sixth Framework Programme for Research and Technological Development
|
||||||
|
- [DILIGENT](https://cordis.europa.eu/project/id/004260) (grant no. 004260).
|
||||||
|
- the Seventh Framework Programme for research, technological development and demonstration
|
||||||
|
- [D4Science](https://cordis.europa.eu/project/id/212488) (grant no. 212488);
|
||||||
|
- [D4Science-II](https://cordis.europa.eu/project/id/239019) (grant no.239019);
|
||||||
|
- [ENVRI](https://cordis.europa.eu/project/id/283465) (grant no. 283465);
|
||||||
|
- [iMarine](https://cordis.europa.eu/project/id/283644) (grant no. 283644);
|
||||||
|
- [EUBrazilOpenBio](https://cordis.europa.eu/project/id/288754) (grant no. 288754).
|
||||||
|
- the H2020 research and innovation programme
|
||||||
|
- [SoBigData](https://cordis.europa.eu/project/id/654024) (grant no. 654024);
|
||||||
|
- [PARTHENOS](https://cordis.europa.eu/project/id/654119) (grant no. 654119);
|
||||||
|
- [EGI-Engage](https://cordis.europa.eu/project/id/654142) (grant no. 654142);
|
||||||
|
- [ENVRI PLUS](https://cordis.europa.eu/project/id/654182) (grant no. 654182);
|
||||||
|
- [BlueBRIDGE](https://cordis.europa.eu/project/id/675680) (grant no. 675680);
|
||||||
|
- [PerformFISH](https://cordis.europa.eu/project/id/727610) (grant no. 727610);
|
||||||
|
- [AGINFRA PLUS](https://cordis.europa.eu/project/id/731001) (grant no. 731001);
|
||||||
|
- [DESIRA](https://cordis.europa.eu/project/id/818194) (grant no. 818194);
|
||||||
|
- [ARIADNEplus](https://cordis.europa.eu/project/id/823914) (grant no. 823914);
|
||||||
|
- [RISIS 2](https://cordis.europa.eu/project/id/824091) (grant no. 824091);
|
||||||
|
- [EOSC-Pillar](https://cordis.europa.eu/project/id/857650) (grant no. 857650);
|
||||||
|
- [Blue Cloud](https://cordis.europa.eu/project/id/862409) (grant no. 862409);
|
||||||
|
- [SoBigData-PlusPlus](https://cordis.europa.eu/project/id/871042) (grant no. 871042);
|
22
README.md
22
README.md
|
@ -54,26 +54,6 @@ open-source software toolkit used for building and operating Hybrid Data
|
||||||
Infrastructures enabling the dynamic deployment of Virtual Research Environments
|
Infrastructures enabling the dynamic deployment of Virtual Research Environments
|
||||||
by favouring the realisation of reuse oriented policies.
|
by favouring the realisation of reuse oriented policies.
|
||||||
|
|
||||||
The projects leading to this software have received funding from a series of European Union programmes including:
|
The projects leading to this software have received funding from a series of European Union programmes see [FUNDING.md](FUNDING.md)
|
||||||
|
|
||||||
- the Sixth Framework Programme for Research and Technological Development
|
|
||||||
- DILIGENT (grant no. 004260).
|
|
||||||
- the Seventh Framework Programme for research, technological development and demonstration
|
|
||||||
- D4Science (grant no. 212488);
|
|
||||||
- D4Science-II (grant no.239019);
|
|
||||||
- ENVRI (grant no. 283465);
|
|
||||||
- iMarine(grant no. 283644);
|
|
||||||
- EUBrazilOpenBio (grant no. 288754).
|
|
||||||
- the H2020 research and innovation programme
|
|
||||||
- SoBigData (grant no. 654024);
|
|
||||||
- PARTHENOS (grant no. 654119);
|
|
||||||
- EGIEngage (grant no. 654142);
|
|
||||||
- ENVRIplus (grant no. 654182);
|
|
||||||
- BlueBRIDGE (grant no. 675680);
|
|
||||||
- PerformFish (grant no. 727610);
|
|
||||||
- AGINFRAplus (grant no. 731001);
|
|
||||||
- DESIRA (grant no. 818194);
|
|
||||||
- ARIADNEplus (grant no. 823914);
|
|
||||||
- RISIS2 (grant no. 824091);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,29 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!DOCTYPE xml>
|
|
||||||
<Resource>
|
|
||||||
<ID />
|
|
||||||
<Type>Service</Type>
|
|
||||||
<Profile>
|
|
||||||
<Description>${description}</Description>
|
|
||||||
<Class>${serviceClass}</Class>
|
|
||||||
<Name>${artifactId}</Name>
|
|
||||||
<Version>1.0.0</Version>
|
|
||||||
<Packages>
|
|
||||||
<Software>
|
|
||||||
<Description>${description}</Description>
|
|
||||||
<Name>${artifactId}</Name>
|
|
||||||
<Version>${version}</Version>
|
|
||||||
<MavenCoordinates>
|
|
||||||
<groupId>${groupId}</groupId>
|
|
||||||
<artifactId>${artifactId}</artifactId>
|
|
||||||
<version>${version}</version>
|
|
||||||
</MavenCoordinates>
|
|
||||||
<Type>Library</Type>
|
|
||||||
<Files>
|
|
||||||
<File>${build.finalName}.${project.packaging}</File>
|
|
||||||
</Files>
|
|
||||||
</Software>
|
|
||||||
</Packages>
|
|
||||||
</Profile>
|
|
||||||
</Resource>
|
|
||||||
|
|
|
@ -1,2 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
||||||
<smartgears version="${project.version}" />
|
|
BIN
endpoint.xml
BIN
endpoint.xml
Binary file not shown.
|
@ -0,0 +1,2 @@
|
||||||
|
[smartgears]
|
||||||
|
version = ${project.version}
|
214
pom.xml
214
pom.xml
|
@ -5,42 +5,64 @@
|
||||||
<parent>
|
<parent>
|
||||||
<artifactId>maven-parent</artifactId>
|
<artifactId>maven-parent</artifactId>
|
||||||
<groupId>org.gcube.tools</groupId>
|
<groupId>org.gcube.tools</groupId>
|
||||||
<version>1.1.0</version>
|
<version>1.2.0</version>
|
||||||
<relativePath />
|
<relativePath />
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<groupId>org.gcube.core</groupId>
|
<groupId>org.gcube.core</groupId>
|
||||||
<artifactId>common-smartgears</artifactId>
|
<artifactId>common-smartgears</artifactId>
|
||||||
<version>3.1.5</version>
|
<version>4.0.0</version>
|
||||||
<name>SmartGears</name>
|
<name>SmartGears</name>
|
||||||
|
|
||||||
<dependencyManagement>
|
<dependencyManagement>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.gcube.distribution</groupId>
|
<groupId>org.gcube.distribution</groupId>
|
||||||
<artifactId>gcube-bom</artifactId>
|
<artifactId>gcube-bom</artifactId>
|
||||||
<version>2.0.1</version>
|
<version>4.0.0</version>
|
||||||
<type>pom</type>
|
<type>pom</type>
|
||||||
<scope>import</scope>
|
<scope>import</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</dependencyManagement>
|
</dependencyManagement>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<distroDirectory>distro</distroDirectory>
|
<tomcat.version>10.1.19</tomcat.version>
|
||||||
<tomcat.version>7.0.42</tomcat.version>
|
|
||||||
<jersey.version>1.17.1</jersey.version>
|
|
||||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
|
<maven.compiler.source>11</maven.compiler.source>
|
||||||
|
<maven.compiler.target>11</maven.compiler.target>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
<scm>
|
<scm>
|
||||||
<connection>scm:git:https://code-repo.d4science.org/gCubeSystem/common-smartgears.git</connection>
|
<connection>
|
||||||
<developerConnection>scm:git:https://code-repo.d4science.org/gCubeSystem/common-smartgears.git</developerConnection>
|
scm:git:https://code-repo.d4science.org/gCubeSystem/common-smartgears.git</connection>
|
||||||
|
<developerConnection>
|
||||||
|
scm:git:httpstps://code-repo.d4science.org/gCubeSystem/common-smartgears.git</developerConnection>
|
||||||
<url>https://code-repo.d4science.org/gCubeSystem/common-smartgears</url>
|
<url>https://code-repo.d4science.org/gCubeSystem/common-smartgears</url>
|
||||||
</scm>
|
</scm>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
|
<!--
|
||||||
|
https://mvnrepository.com/artifact/jakarta.servlet/jakarta.servlet-api -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>jakarta.servlet</groupId>
|
||||||
|
<artifactId>jakarta.servlet-api</artifactId>
|
||||||
|
<version>6.0.0</version>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.reflections</groupId>
|
||||||
|
<artifactId>reflections</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.yaml</groupId>
|
||||||
|
<artifactId>snakeyaml</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.github.classgraph</groupId>
|
||||||
|
<artifactId>classgraph</artifactId>
|
||||||
|
<version>4.8.28</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.gcube.common</groupId>
|
||||||
|
<artifactId>health-api</artifactId>
|
||||||
|
<version>[1.0.0-SNAPSHOT, 2.0.0-SNAPSHOT)</version>
|
||||||
|
</dependency>
|
||||||
<!-- gCube Jackson -->
|
<!-- gCube Jackson -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.gcube.common</groupId>
|
<groupId>org.gcube.common</groupId>
|
||||||
|
@ -55,146 +77,83 @@
|
||||||
<artifactId>gcube-jackson-core</artifactId>
|
<artifactId>gcube-jackson-core</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
<!-- END gCube Jackson -->
|
<!-- END gCube Jackson -->
|
||||||
|
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.gcube.common</groupId>
|
<groupId>org.gcube.common</groupId>
|
||||||
<artifactId>authorization-client</artifactId>
|
<artifactId>common-security</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.gcube.common</groupId>
|
|
||||||
<artifactId>common-authorization</artifactId>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.gcube.data.publishing</groupId>
|
<groupId>org.gcube.data.publishing</groupId>
|
||||||
<artifactId>document-store-lib</artifactId>
|
<artifactId>document-store-lib</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.gcube.accounting</groupId>
|
<groupId>org.gcube.accounting</groupId>
|
||||||
<artifactId>accounting-lib</artifactId>
|
<artifactId>accounting-lib</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.slf4j</groupId>
|
<groupId>org.slf4j</groupId>
|
||||||
<artifactId>slf4j-api</artifactId>
|
<artifactId>slf4j-api</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.gcube.resources</groupId>
|
<groupId>org.ini4j</groupId>
|
||||||
<artifactId>registry-publisher</artifactId>
|
<artifactId>ini4j</artifactId>
|
||||||
|
<version>0.5.4</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.gcube.resources</groupId>
|
|
||||||
<artifactId>common-gcore-resources</artifactId>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.gcube.core</groupId>
|
<groupId>org.gcube.core</groupId>
|
||||||
<artifactId>common-validator</artifactId>
|
<artifactId>common-validator</artifactId>
|
||||||
<version>[1.0.0,2.0.0-SNAPSHOT)</version>
|
<version>[1.0.0,2.0.0-SNAPSHOT)</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.gcube.core</groupId>
|
|
||||||
<artifactId>common-scope</artifactId>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.gcube.core</groupId>
|
<groupId>org.gcube.core</groupId>
|
||||||
<artifactId>common-events</artifactId>
|
<artifactId>common-events</artifactId>
|
||||||
<version>[1.0.0,2.0.0-SNAPSHOT)</version>
|
<version>[1.0.0,2.0.0-SNAPSHOT)</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>javax.servlet</groupId>
|
<groupId>org.gcube.common.security</groupId>
|
||||||
<artifactId>javax.servlet-api</artifactId>
|
<artifactId>gcube-secrets</artifactId>
|
||||||
<version>3.0.1</version>
|
|
||||||
<scope>provided</scope>
|
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<!-- https://mvnrepository.com/artifact/io.micrometer/micrometer-core -->
|
||||||
|
|
||||||
<!-- ***************** test ******************* -->
|
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.jboss.shrinkwrap.resolver</groupId>
|
<groupId>io.micrometer</groupId>
|
||||||
<artifactId>shrinkwrap-resolver-depchain</artifactId>
|
<artifactId>micrometer-core</artifactId>
|
||||||
<version>2.0.0-beta-2</version>
|
<version>1.9.0</version>
|
||||||
<type>pom</type>
|
|
||||||
<scope>test</scope>
|
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
<!-- https://mvnrepository.com/artifact/org.apache.tomcat/tomcat-catalina -->
|
<groupId>io.micrometer</groupId>
|
||||||
|
<artifactId>micrometer-registry-prometheus</artifactId>
|
||||||
|
<version>1.9.0</version>
|
||||||
|
</dependency>
|
||||||
|
<!--
|
||||||
|
https://mvnrepository.com/artifact/org.apache.tomcat/tomcat-catalina -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.apache.tomcat</groupId>
|
<groupId>org.apache.tomcat</groupId>
|
||||||
<artifactId>tomcat-catalina</artifactId>
|
<artifactId>tomcat-catalina</artifactId>
|
||||||
<version>${tomcat.version}</version>
|
<version>${tomcat.version}</version>
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.apache.tomcat.embed</groupId>
|
|
||||||
<artifactId>tomcat-embed-core</artifactId>
|
|
||||||
<version>${tomcat.version}</version>
|
|
||||||
<scope>test</scope>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.sun.jersey</groupId>
|
|
||||||
<artifactId>jersey-client</artifactId>
|
|
||||||
<version>${jersey.version}</version>
|
|
||||||
<scope>test</scope>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.apache.tomcat.embed</groupId>
|
|
||||||
<artifactId>tomcat-embed-core</artifactId>
|
|
||||||
<version>${tomcat.version}</version>
|
|
||||||
<scope>test</scope>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.apache.tomcat.embed</groupId>
|
|
||||||
<artifactId>tomcat-embed-logging-log4j</artifactId>
|
|
||||||
<version>${tomcat.version}</version>
|
|
||||||
<scope>test</scope>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.apache.tomcat.embed</groupId>
|
|
||||||
<artifactId>tomcat-embed-jasper</artifactId>
|
|
||||||
<version>${tomcat.version}</version>
|
|
||||||
<scope>test</scope>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>junit</groupId>
|
<groupId>junit</groupId>
|
||||||
<artifactId>junit</artifactId>
|
<artifactId>junit</artifactId>
|
||||||
<version>4.10</version>
|
<version>4.10</version>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>ch.qos.logback</groupId>
|
<groupId>ch.qos.logback</groupId>
|
||||||
<artifactId>logback-classic</artifactId>
|
<artifactId>logback-classic</artifactId>
|
||||||
<scope>runtime</scope>
|
<scope>runtime</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.mockito</groupId>
|
<groupId>org.mockito</groupId>
|
||||||
<artifactId>mockito-core</artifactId>
|
<artifactId>mockito-core</artifactId>
|
||||||
<version>1.9.0</version>
|
<version>1.9.0</version>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.gcube.resources</groupId>
|
||||||
|
<artifactId>common-gcore-resources</artifactId>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
|
|
||||||
<plugins>
|
<plugins>
|
||||||
<!-- excludes probe package from jar -->
|
<!-- excludes probe package from jar -->
|
||||||
<plugin>
|
<plugin>
|
||||||
|
@ -215,7 +174,18 @@
|
||||||
</execution>
|
</execution>
|
||||||
</executions>
|
</executions>
|
||||||
</plugin>
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-surefire-plugin</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<systemPropertyVariables>
|
||||||
|
<property>
|
||||||
|
<name>projectVersion</name>
|
||||||
|
<value>${project.version}</value>
|
||||||
|
</property>
|
||||||
|
</systemPropertyVariables>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
<!-- include probe in attached war -->
|
<!-- include probe in attached war -->
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
@ -224,8 +194,8 @@
|
||||||
<configuration>
|
<configuration>
|
||||||
<primaryArtifact>false</primaryArtifact>
|
<primaryArtifact>false</primaryArtifact>
|
||||||
<classifier>probe</classifier>
|
<classifier>probe</classifier>
|
||||||
|
<packagingIncludes>
|
||||||
<packagingIncludes>WEB-INF/classes/org/gcube/smartgears/probe/**/*</packagingIncludes>
|
WEB-INF/classes/org/gcube/smartgears/probe/**/*</packagingIncludes>
|
||||||
<failOnMissingWebXml>false</failOnMissingWebXml>
|
<failOnMissingWebXml>false</failOnMissingWebXml>
|
||||||
</configuration>
|
</configuration>
|
||||||
<executions>
|
<executions>
|
||||||
|
@ -238,48 +208,6 @@
|
||||||
</execution>
|
</execution>
|
||||||
</executions>
|
</executions>
|
||||||
</plugin>
|
</plugin>
|
||||||
|
|
||||||
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-surefire-plugin</artifactId>
|
|
||||||
<!-- version>2.15</version -->
|
|
||||||
<configuration>
|
|
||||||
<!-- tomcat annotation discovery won't work with the default manifest-only
|
|
||||||
jar -->
|
|
||||||
<useManifestOnlyJar>false</useManifestOnlyJar>
|
|
||||||
</configuration>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-resources-plugin</artifactId>
|
|
||||||
<version>2.6</version>
|
|
||||||
<executions>
|
|
||||||
<!-- interpolates and copies configuration.properties -->
|
|
||||||
<execution>
|
|
||||||
<id>copy-configuration</id>
|
|
||||||
<goals>
|
|
||||||
<goal>copy-resources</goal>
|
|
||||||
</goals>
|
|
||||||
<phase>validate</phase>
|
|
||||||
<configuration>
|
|
||||||
<outputDirectory>src/main/resources/META-INF</outputDirectory>
|
|
||||||
<overwrite>true</overwrite>
|
|
||||||
<encoding>UTF-8</encoding>
|
|
||||||
<resources>
|
|
||||||
<resource>
|
|
||||||
<directory>${distroDirectory}</directory>
|
|
||||||
<includes>
|
|
||||||
<include>smartgears-config.xml</include>
|
|
||||||
</includes>
|
|
||||||
<filtering>true</filtering>
|
|
||||||
</resource>
|
|
||||||
</resources>
|
|
||||||
</configuration>
|
|
||||||
</execution>
|
|
||||||
</executions>
|
|
||||||
</plugin>
|
|
||||||
|
|
||||||
</plugins>
|
</plugins>
|
||||||
</build>
|
</build>
|
||||||
</project>
|
</project>
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
package org.gcube.smartgears;
|
package org.gcube.smartgears;
|
||||||
|
|
||||||
|
import static java.util.Collections.emptyList;
|
||||||
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import javax.servlet.ServletContainerInitializer;
|
import jakarta.servlet.ServletContainerInitializer;
|
||||||
import javax.servlet.ServletContext;
|
import jakarta.servlet.ServletContext;
|
||||||
import javax.servlet.ServletException;
|
import jakarta.servlet.ServletException;
|
||||||
|
|
||||||
import org.gcube.smartgears.context.application.ApplicationContext;
|
import org.gcube.smartgears.context.application.ApplicationContext;
|
||||||
import org.gcube.smartgears.context.container.ContainerContext;
|
import org.gcube.smartgears.context.container.ContainerContext;
|
||||||
|
@ -14,6 +16,19 @@ import org.gcube.smartgears.provider.ProviderFactory;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import io.micrometer.core.instrument.Metrics;
|
||||||
|
import io.micrometer.core.instrument.binder.jvm.ClassLoaderMetrics;
|
||||||
|
import io.micrometer.core.instrument.binder.jvm.JvmGcMetrics;
|
||||||
|
import io.micrometer.core.instrument.binder.jvm.JvmInfoMetrics;
|
||||||
|
import io.micrometer.core.instrument.binder.jvm.JvmMemoryMetrics;
|
||||||
|
import io.micrometer.core.instrument.binder.jvm.JvmThreadMetrics;
|
||||||
|
import io.micrometer.core.instrument.binder.logging.LogbackMetrics;
|
||||||
|
import io.micrometer.core.instrument.binder.system.ProcessorMetrics;
|
||||||
|
import io.micrometer.core.instrument.binder.system.UptimeMetrics;
|
||||||
|
import io.micrometer.core.instrument.binder.tomcat.TomcatMetrics;
|
||||||
|
import io.micrometer.prometheus.PrometheusConfig;
|
||||||
|
import io.micrometer.prometheus.PrometheusMeterRegistry;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Bootstraps management of all deployed applications which require it.
|
* Bootstraps management of all deployed applications which require it.
|
||||||
*
|
*
|
||||||
|
@ -34,6 +49,8 @@ public class Bootstrap implements ServletContainerInitializer {
|
||||||
|
|
||||||
public Bootstrap() {
|
public Bootstrap() {
|
||||||
|
|
||||||
|
log.info("bootstrap started the container");
|
||||||
|
|
||||||
if (smartgearsHasStarted)
|
if (smartgearsHasStarted)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -51,6 +68,8 @@ public class Bootstrap implements ServletContainerInitializer {
|
||||||
|
|
||||||
ApplicationManager appManager = new ApplicationManager();
|
ApplicationManager appManager = new ApplicationManager();
|
||||||
|
|
||||||
|
log.info("check if is managed @ {}", application.getContextPath());
|
||||||
|
|
||||||
//act only on resources
|
//act only on resources
|
||||||
if (isResource(application)) {
|
if (isResource(application)) {
|
||||||
|
|
||||||
|
@ -72,25 +91,45 @@ public class Bootstrap implements ServletContainerInitializer {
|
||||||
+ " (see cause)", t);
|
+ " (see cause)", t);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
} else log.info("is not managed @ {}", application.getContextPath());
|
||||||
}
|
}
|
||||||
|
|
||||||
// helpers
|
// helpers
|
||||||
|
@SuppressWarnings("resource")
|
||||||
private void initialiseContainer() {
|
private void initialiseContainer() {
|
||||||
|
|
||||||
|
ClassLoader contextCL = Thread.currentThread().getContextClassLoader();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
// TODO Ask why is needed?
|
||||||
|
Thread.currentThread().setContextClassLoader(ContainerManager.class.getClassLoader());
|
||||||
|
|
||||||
log.trace("smartgears is starting");
|
log.trace("smartgears is starting");
|
||||||
|
|
||||||
|
|
||||||
/* Get the ContainerContext. Look at DefaultProvider */
|
/* Get the ContainerContext. Look at DefaultProvider */
|
||||||
context = ProviderFactory.provider().containerContext();
|
context = ProviderFactory.provider().containerContext();
|
||||||
|
|
||||||
|
PrometheusMeterRegistry registry = new PrometheusMeterRegistry(PrometheusConfig.DEFAULT);
|
||||||
|
|
||||||
|
new ClassLoaderMetrics().bindTo(registry);
|
||||||
|
new JvmMemoryMetrics().bindTo(registry);
|
||||||
|
new JvmGcMetrics().bindTo(registry);
|
||||||
|
new ProcessorMetrics().bindTo(registry);
|
||||||
|
new JvmThreadMetrics().bindTo(registry);
|
||||||
|
new UptimeMetrics().bindTo(registry);
|
||||||
|
new ProcessorMetrics().bindTo(registry);
|
||||||
|
new TomcatMetrics(null, emptyList()).bindTo(registry);
|
||||||
|
new LogbackMetrics().bindTo(registry);
|
||||||
|
new JvmInfoMetrics().bindTo(registry);
|
||||||
|
|
||||||
|
Metrics.addRegistry(registry);
|
||||||
|
|
||||||
|
|
||||||
/* Validate the configuration retrieved by ContainerContext
|
/* Validate the configuration retrieved by ContainerContext
|
||||||
* using gcube facilities annotation based
|
* using gcube facilities annotation based
|
||||||
* ( i.e org.gcube.common.validator.annotations)
|
* ( i.e org.gcube.common.validator.annotations)
|
||||||
*/
|
*/
|
||||||
//context.configuration().validate();
|
context.configuration().validate();
|
||||||
|
|
||||||
} catch (RuntimeException e) {
|
} catch (RuntimeException e) {
|
||||||
|
|
||||||
|
@ -100,6 +139,8 @@ public class Bootstrap implements ServletContainerInitializer {
|
||||||
|
|
||||||
//we let the container continue
|
//we let the container continue
|
||||||
|
|
||||||
|
} finally {//restore the classloader of the current application
|
||||||
|
Thread.currentThread().setContextClassLoader(contextCL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
package org.gcube.smartgears;
|
package org.gcube.smartgears;
|
||||||
|
|
||||||
import org.gcube.smartgears.extensions.resource.RemoteResource;
|
import org.gcube.smartgears.extensions.resource.RemoteResource;
|
||||||
import org.gcube.smartgears.handlers.application.lifecycle.ProfileManager;
|
import org.gcube.smartgears.handlers.application.request.RequestAccounting;
|
||||||
import org.gcube.smartgears.handlers.application.request.RequestValidator;
|
import org.gcube.smartgears.handlers.application.request.RequestValidator;
|
||||||
import org.gcube.smartgears.handlers.container.lifecycle.AccountingManager;
|
import org.gcube.smartgears.handlers.container.lifecycle.AccountingManager;
|
||||||
|
|
||||||
|
@ -28,7 +28,7 @@ public class Constants {
|
||||||
/**
|
/**
|
||||||
* The container configuration file path, relative to the container configuration directory.
|
* The container configuration file path, relative to the container configuration directory.
|
||||||
*/
|
*/
|
||||||
public static final String container_configuraton_file_path = "container.xml";
|
public static final String container_configuraton_file_path = "container.ini";
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -36,25 +36,15 @@ public class Constants {
|
||||||
*/
|
*/
|
||||||
public static final String container_profile_file_path = "ghn.xml";
|
public static final String container_profile_file_path = "ghn.xml";
|
||||||
|
|
||||||
|
/*
|
||||||
public static final String container_profile_file_path_copy = "ghn.xml.copy";
|
public static final String container_profile_file_path_copy = "ghn.xml.copy";
|
||||||
|
|
||||||
/**
|
|
||||||
* The container lifecycle configuration resource path.
|
|
||||||
*/
|
*/
|
||||||
public static final String container_handlers_file_path = "/META-INF/container-handlers.xml";
|
|
||||||
|
|
||||||
public static final String container_handlers_file_name = "gcube-container-handlers.xml";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The library configuration resource path.
|
|
||||||
*/
|
|
||||||
public static final String library_configuration_file_path = "/META-INF/smartgears-config.xml";
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The name of the context property that contains the node profile.
|
* The name of the context property that contains the node profile.
|
||||||
*/
|
|
||||||
public static final String container_profile_property = "ghn-profile";
|
|
||||||
|
|
||||||
|
public static final String container_profile_property = "ghn-profile";
|
||||||
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The default value of for the container publication frequency.
|
* The default value of for the container publication frequency.
|
||||||
|
@ -62,24 +52,11 @@ public class Constants {
|
||||||
public static final long default_container_publication_frequency_in_seconds = 60;
|
public static final long default_container_publication_frequency_in_seconds = 60;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The application configuration resource path.
|
* The application configuration resource path.
|
||||||
*/
|
*/
|
||||||
public static final String configuration_file_path = "/WEB-INF/gcube-app.xml";
|
public static final String configuration_file_path = "/WEB-INF/application.yaml";
|
||||||
|
|
||||||
/**
|
|
||||||
* The application lifecycle configuration resource path.
|
|
||||||
*/
|
|
||||||
public static final String handlers_file_path = "/WEB-INF/gcube-handlers.xml";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The default application lifecycle configuration resource path.
|
|
||||||
*/
|
|
||||||
public static final String default_handlers_file_path = "/META-INF/default-handlers.xml";
|
|
||||||
|
|
||||||
public static final String application_handlers_file_name = "gcube-application-handlers.xml";
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The wildcard exclude directive.
|
* The wildcard exclude directive.
|
||||||
|
@ -92,16 +69,6 @@ public class Constants {
|
||||||
*/
|
*/
|
||||||
public static final String root_mapping = "/gcube/resource";
|
public static final String root_mapping = "/gcube/resource";
|
||||||
|
|
||||||
/**
|
|
||||||
* The application extensions configuration resource path.
|
|
||||||
*/
|
|
||||||
public static final String extensions_file_path = "/WEB-INF/gcube-extensions.xml";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The default application extensions configuration resource path.
|
|
||||||
*/
|
|
||||||
public static final String default_extensions_file_path = "/META-INF/default-extensions.xml";
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The application frontpage resource path.
|
* The application frontpage resource path.
|
||||||
*/
|
*/
|
||||||
|
@ -117,6 +84,11 @@ public class Constants {
|
||||||
*/
|
*/
|
||||||
public static final String request_validation = "request-validation";
|
public static final String request_validation = "request-validation";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The configuration name of {@link RequestMetrics}s.
|
||||||
|
*/
|
||||||
|
public static final String request_metrics = "request-metrics";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The configuration name of {@link RequestValidator}s.
|
* The configuration name of {@link RequestValidator}s.
|
||||||
*/
|
*/
|
||||||
|
@ -140,8 +112,6 @@ public class Constants {
|
||||||
public static final String remote_management = "remote-management";
|
public static final String remote_management = "remote-management";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The path of the application profile file, relative to the service configuration directory.
|
* The path of the application profile file, relative to the service configuration directory.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -0,0 +1,37 @@
|
||||||
|
package org.gcube.smartgears.configuration;
|
||||||
|
|
||||||
|
import org.gcube.common.security.credentials.Credentials;
|
||||||
|
import org.gcube.common.security.factories.AuthorizationProviderFactory;
|
||||||
|
import org.gcube.common.validator.annotations.IsValid;
|
||||||
|
import org.gcube.common.validator.annotations.NotNull;
|
||||||
|
|
||||||
|
public class AuthorizationProviderConfiguration {
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
AuthorizationProviderFactory<?> authProviderFactory;
|
||||||
|
|
||||||
|
@NotNull @IsValid
|
||||||
|
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,11 @@
|
||||||
|
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 {
|
||||||
|
|
||||||
|
String getLocation();
|
||||||
|
}
|
|
@ -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,200 @@
|
||||||
package org.gcube.smartgears.configuration.application;
|
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 java.util.Set;
|
||||||
|
|
||||||
import org.gcube.smartgears.configuration.Mode;
|
import org.gcube.com.fasterxml.jackson.annotation.JsonAutoDetect;
|
||||||
import org.gcube.smartgears.persistence.Persistence;
|
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.
|
* The configuration of a managed app.
|
||||||
|
* <p>
|
||||||
|
* Includes the list of its client services.
|
||||||
*
|
*
|
||||||
* @author Fabio Simeoni
|
* @author Lucio Lelii
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public interface ApplicationConfiguration {
|
@JsonInclude(value = Include.NON_NULL)
|
||||||
|
@JsonAutoDetect(fieldVisibility = Visibility.ANY)
|
||||||
|
public class ApplicationConfiguration {
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
String name;
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
String group;
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
String version;
|
||||||
|
|
||||||
|
String description="";
|
||||||
|
|
||||||
|
@JsonIgnore
|
||||||
|
String context;
|
||||||
|
|
||||||
|
private boolean proxable = true;
|
||||||
|
|
||||||
|
Set<GCubeExclude> excludes= new HashSet<>();
|
||||||
|
|
||||||
|
Set<GCubeInclude> includes= new HashSet<>();
|
||||||
|
|
||||||
|
@NotEmpty @JsonProperty("persistence")
|
||||||
|
PersistenceConfiguration persistenceConfiguration;
|
||||||
|
|
||||||
|
@JsonProperty("allowed-secrets")
|
||||||
|
List<String> allowedSecretClasses = null;
|
||||||
|
|
||||||
|
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 allowedSecrets(String ... classNames) {
|
||||||
|
this.allowedSecretClasses = Arrays.asList(classNames);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> allowedSecrets(){
|
||||||
|
return this.allowedSecretClasses;
|
||||||
|
}
|
||||||
|
|
||||||
|
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) {
|
||||||
* Returns the management mode of the application.
|
this.group=group;
|
||||||
* @return the management mode
|
return this;
|
||||||
*/
|
}
|
||||||
Mode mode();
|
|
||||||
|
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) {
|
||||||
* Returns the context path of the application
|
this.description=description;
|
||||||
* @return the context path
|
return this;
|
||||||
*/
|
}
|
||||||
String context();
|
|
||||||
|
|
||||||
boolean proxied();
|
public boolean proxable() {
|
||||||
|
return proxable;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
public PersistenceConfiguration persistenceConfiguration() {
|
||||||
* Sets the context path of the application
|
return persistenceConfiguration;
|
||||||
* @param context the context path
|
}
|
||||||
* @return this configuration
|
|
||||||
*/
|
|
||||||
ApplicationConfiguration context(String context);
|
|
||||||
|
|
||||||
/**
|
public void validate() {
|
||||||
* Sets the management mode of this application.
|
|
||||||
* @param the management mode
|
|
||||||
* @return this configuration
|
|
||||||
*/
|
|
||||||
ApplicationConfiguration mode(Mode mode);
|
|
||||||
|
|
||||||
|
List<String> msgs = new ArrayList<String>();
|
||||||
|
|
||||||
/**
|
Validator validator = ValidatorFactory.validator();
|
||||||
* Returns the name of the application.
|
|
||||||
* @return the name
|
|
||||||
*/
|
|
||||||
String name();
|
|
||||||
|
|
||||||
|
for (ValidationError error : validator.validate(this))
|
||||||
|
msgs.add(error.toString());
|
||||||
|
|
||||||
/**
|
if (!this.excludes().isEmpty() && !this.includes().isEmpty())
|
||||||
* Sets the name of the application.
|
msgs.add("exclude tags and includes tags are mutually exclusive");
|
||||||
* @param name the name
|
|
||||||
* @return this configuration
|
|
||||||
*/
|
|
||||||
ApplicationConfiguration name(String name);
|
|
||||||
|
|
||||||
/**
|
if (!msgs.isEmpty())
|
||||||
* Returns the class of the application
|
throw new IllegalStateException("invalid configuration: "+msgs);
|
||||||
* @return the class
|
}
|
||||||
*/
|
|
||||||
String serviceClass();
|
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* Sets the class of the application.
|
public int hashCode() {
|
||||||
* @param serviceClass the class
|
return Objects.hash(description, excludes, group, includes, name, proxable, version, allowedSecretClasses);
|
||||||
* @return this configuration
|
}
|
||||||
*/
|
|
||||||
ApplicationConfiguration serviceClass(String serviceClass);
|
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* Returns the version of the application.
|
public boolean equals(Object obj) {
|
||||||
* @return the version
|
if (this == obj)
|
||||||
*/
|
return true;
|
||||||
String version();
|
if (obj == null)
|
||||||
|
return false;
|
||||||
/**
|
if (getClass() != obj.getClass())
|
||||||
* Sets the version of the application.
|
return false;
|
||||||
* @param version the version
|
ApplicationConfiguration other = (ApplicationConfiguration) obj;
|
||||||
* @return this configuration
|
return Objects.equals(description, other.description)
|
||||||
*/
|
&& Objects.equals(excludes, other.excludes) && Objects.equals(group, other.group)
|
||||||
ApplicationConfiguration version(String version);
|
&& Objects.equals(includes, other.includes) && Objects.equals(name, other.name)
|
||||||
|
&& proxable == other.proxable && Objects.equals(version, other.version);
|
||||||
/**
|
}
|
||||||
* Returns the description of the application.
|
|
||||||
* @return the description
|
|
||||||
*/
|
|
||||||
String description();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the description of the application.
|
|
||||||
* @param description the description
|
|
||||||
* @return this configuration
|
|
||||||
*/
|
|
||||||
ApplicationConfiguration description(String description);
|
|
||||||
|
|
||||||
ProxyAddress proxyAddress();
|
|
||||||
|
|
||||||
ApplicationConfiguration proxyAddress(ProxyAddress proxyaddress);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the tokens in which the application operates when it first starts.
|
|
||||||
* @return the tokens
|
|
||||||
*/
|
|
||||||
Set<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();
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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);
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "ApplicationConfiguration [name=" + name + ", group=" + group + ", version=" + version + ", description="
|
||||||
|
+ description + ", context=" + context + ", proxable=" + proxable + ", excludes=" + excludes
|
||||||
|
+ ", includes=" + includes + ", persistenceConfiguration=" + persistenceConfiguration
|
||||||
|
+ ", allowedSecretClasses=" + this.allowedSecretClasses + "]";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
|
@ -1,18 +1,22 @@
|
||||||
package org.gcube.smartgears.configuration.application;
|
package org.gcube.smartgears.configuration.application;
|
||||||
|
|
||||||
import static org.gcube.smartgears.utils.Utils.*;
|
import java.io.File;
|
||||||
|
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.lang.reflect.Modifier;
|
import java.util.LinkedList;
|
||||||
import java.util.HashSet;
|
import java.util.List;
|
||||||
import java.util.ServiceLoader;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
import javax.xml.bind.JAXBContext;
|
import org.gcube.com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
import javax.xml.bind.JAXBException;
|
import org.gcube.smartgears.configuration.PersistenceConfiguration;
|
||||||
|
import org.gcube.smartgears.handlers.application.ApplicationLifecycleHandler;
|
||||||
import org.gcube.smartgears.extensions.ApplicationExtension;
|
import org.gcube.smartgears.handlers.application.RequestHandler;
|
||||||
import org.gcube.smartgears.handlers.application.ApplicationHandler;
|
import org.gcube.smartgears.handlers.application.lifecycle.ApplicationProfileManager;
|
||||||
|
import org.gcube.smartgears.handlers.application.request.RequestAccounting;
|
||||||
|
import org.gcube.smartgears.handlers.application.request.RequestMetrics;
|
||||||
|
import org.gcube.smartgears.handlers.application.request.RequestValidator;
|
||||||
|
import org.gcube.smartgears.persistence.LocalWriter;
|
||||||
|
import org.gcube.smartgears.persistence.LocalWriterConfiguration;
|
||||||
|
import org.gcube.smartgears.utils.Utils;
|
||||||
|
import org.yaml.snakeyaml.Yaml;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Binds {@link ApplicationConfiguration}s to and from XML serialisations.
|
* Binds {@link ApplicationConfiguration}s to and from XML serialisations.
|
||||||
|
@ -29,21 +33,30 @@ public class ApplicationConfigurationBinder {
|
||||||
* @return the configuration
|
* @return the configuration
|
||||||
* @throws RuntimeException if the serialisation is invalid
|
* @throws RuntimeException if the serialisation is invalid
|
||||||
*/
|
*/
|
||||||
public ApplicationConfiguration bind(InputStream stream) {
|
public ApplicationConfiguration load(InputStream stream) {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
Yaml yaml = new Yaml();
|
||||||
|
ObjectMapper mapper = new ObjectMapper();
|
||||||
|
String mapAsString = mapper.writeValueAsString(yaml.load(stream));
|
||||||
|
|
||||||
JAXBContext ctx = JAXBContext.newInstance(DefaultApplicationConfiguration.class);
|
System.out.println(mapAsString);
|
||||||
|
|
||||||
return (ApplicationConfiguration) ctx.createUnmarshaller().unmarshal(stream);
|
ApplicationConfiguration conf = mapper.readValue(mapAsString, ApplicationConfiguration.class);
|
||||||
|
|
||||||
} catch (JAXBException e) {
|
if (conf.persistenceConfiguration() == null) {
|
||||||
|
String location = String.format("%s/state/%s_%s", Utils.home(), conf.group(), conf.name());
|
||||||
|
File dir = new File(location);
|
||||||
|
if (!dir.exists())
|
||||||
|
dir.mkdirs();
|
||||||
|
|
||||||
throw new RuntimeException("invalid service configuration", e);
|
conf.persistenceConfiguration(
|
||||||
|
new PersistenceConfiguration(LocalWriter.class, new LocalWriterConfiguration(location)));
|
||||||
|
|
||||||
}
|
}
|
||||||
finally {
|
|
||||||
closeSafely(stream);
|
return conf;
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,25 +67,26 @@ public class ApplicationConfigurationBinder {
|
||||||
* @return the handlers
|
* @return the handlers
|
||||||
* @throws RuntimeException if the serialisation is invalid
|
* @throws RuntimeException if the serialisation is invalid
|
||||||
*/
|
*/
|
||||||
public ApplicationHandlers bindHandlers(InputStream stream) {
|
public ApplicationHandlers bindHandlers(ClassLoader classLoader) {
|
||||||
|
|
||||||
//collects handler classes
|
List<RequestHandler> requestHandlers = new LinkedList<RequestHandler>();
|
||||||
Set<Class<?>> classes = scanForHandlers();
|
|
||||||
|
|
||||||
try {
|
// ADDING BASE Handler (order is important)
|
||||||
|
requestHandlers.add(new RequestMetrics());
|
||||||
|
requestHandlers.add(new RequestValidator());
|
||||||
|
requestHandlers.add(new RequestAccounting());
|
||||||
|
|
||||||
JAXBContext ctx = JAXBContext.newInstance(classes.toArray(new Class<?>[0]));
|
// TODO scan RequestHAndler form classloader
|
||||||
|
|
||||||
return (ApplicationHandlers) ctx.createUnmarshaller().unmarshal(stream);
|
List<ApplicationLifecycleHandler> lifecycleHandlers = new LinkedList<ApplicationLifecycleHandler>();
|
||||||
|
|
||||||
} catch (JAXBException e) {
|
// ADDING BASE Handler (order is important)
|
||||||
|
lifecycleHandlers.add(new ApplicationProfileManager());
|
||||||
|
|
||||||
throw unchecked(e);
|
// TODO scan ApplicationLifecycleHandler form classloader
|
||||||
|
|
||||||
|
return new ApplicationHandlers(lifecycleHandlers, requestHandlers);
|
||||||
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
closeSafely(stream);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -81,69 +95,54 @@ public class ApplicationConfigurationBinder {
|
||||||
* @param stream the serialisation
|
* @param stream the serialisation
|
||||||
* @return the extensions
|
* @return the extensions
|
||||||
* @throws RuntimeException if the serialisation is invalid
|
* @throws RuntimeException if the serialisation is invalid
|
||||||
|
*
|
||||||
|
* public ApplicationExtensions
|
||||||
|
* bindExtensions(InputStream stream) {
|
||||||
|
*
|
||||||
|
* //collects handler classes Set<Class<?>> classes =
|
||||||
|
* scanForExtensions();
|
||||||
|
*
|
||||||
|
* try {
|
||||||
|
*
|
||||||
|
* JAXBContext ctx =
|
||||||
|
* JAXBContext.newInstance(classes.toArray(new
|
||||||
|
* Class<?>[0]));
|
||||||
|
*
|
||||||
|
* return (ApplicationExtensions)
|
||||||
|
* ctx.createUnmarshaller().unmarshal(stream);
|
||||||
|
*
|
||||||
|
* } catch (JAXBException e) {
|
||||||
|
*
|
||||||
|
* throw unchecked(e);
|
||||||
|
*
|
||||||
|
* } finally { closeSafely(stream); } }
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* private Set<Class<?>> scanForExtensions() throws
|
||||||
|
* RuntimeException {
|
||||||
|
*
|
||||||
|
* @SuppressWarnings("all")
|
||||||
|
* ServiceLoader<ApplicationExtension> handlerLoader =
|
||||||
|
* (ServiceLoader)
|
||||||
|
* ServiceLoader.load(ApplicationExtension.class);
|
||||||
|
*
|
||||||
|
* Set<Class<?>> scanned = new HashSet<Class<?>>();
|
||||||
|
*
|
||||||
|
* for (ApplicationExtension handler : handlerLoader) {
|
||||||
|
* Class<?> handlerClass = handler.getClass(); if
|
||||||
|
* (handlerClass.isInterface() ||
|
||||||
|
* handlerClass.getModifiers() == Modifier.ABSTRACT)
|
||||||
|
* continue; else scanned.add(handlerClass); }
|
||||||
|
*
|
||||||
|
* //add top-level configuration
|
||||||
|
* scanned.add(ApplicationExtensions.class);
|
||||||
|
*
|
||||||
|
* return scanned; }
|
||||||
*/
|
*/
|
||||||
public ApplicationExtensions bindExtensions(InputStream stream) {
|
|
||||||
|
|
||||||
//collects handler classes
|
public void scanForApplicationHandlers(ClassLoader currentClassLoader) {
|
||||||
Set<Class<?>> classes = scanForExtensions();
|
// TODO Auto-generated method stub
|
||||||
|
|
||||||
try {
|
|
||||||
|
|
||||||
JAXBContext ctx = JAXBContext.newInstance(classes.toArray(new Class<?>[0]));
|
|
||||||
|
|
||||||
return (ApplicationExtensions) ctx.createUnmarshaller().unmarshal(stream);
|
|
||||||
|
|
||||||
} catch (JAXBException e) {
|
|
||||||
|
|
||||||
throw unchecked(e);
|
|
||||||
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
closeSafely(stream);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private Set<Class<?>> scanForHandlers() throws RuntimeException {
|
|
||||||
|
|
||||||
@SuppressWarnings("all")
|
|
||||||
ServiceLoader<ApplicationHandler> handlerLoader = (ServiceLoader) ServiceLoader.load(ApplicationHandler.class);
|
|
||||||
|
|
||||||
Set<Class<?>> scanned = new HashSet<Class<?>>();
|
|
||||||
|
|
||||||
for (ApplicationHandler<?> handler : handlerLoader) {
|
|
||||||
Class<?> handlerClass = handler.getClass();
|
|
||||||
if (handlerClass.isInterface() || handlerClass.getModifiers() == Modifier.ABSTRACT)
|
|
||||||
continue;
|
|
||||||
else
|
|
||||||
scanned.add(handlerClass);
|
|
||||||
}
|
|
||||||
|
|
||||||
//add top-level configuration
|
|
||||||
scanned.add(ApplicationHandlers.class);
|
|
||||||
|
|
||||||
return scanned;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Set<Class<?>> scanForExtensions() throws RuntimeException {
|
|
||||||
|
|
||||||
@SuppressWarnings("all")
|
|
||||||
ServiceLoader<ApplicationExtension> handlerLoader = (ServiceLoader) ServiceLoader.load(ApplicationExtension.class);
|
|
||||||
|
|
||||||
Set<Class<?>> scanned = new HashSet<Class<?>>();
|
|
||||||
|
|
||||||
for (ApplicationExtension handler : handlerLoader) {
|
|
||||||
Class<?> handlerClass = handler.getClass();
|
|
||||||
if (handlerClass.isInterface() || handlerClass.getModifiers() == Modifier.ABSTRACT)
|
|
||||||
continue;
|
|
||||||
else
|
|
||||||
scanned.add(handlerClass);
|
|
||||||
}
|
|
||||||
|
|
||||||
//add top-level configuration
|
|
||||||
scanned.add(ApplicationExtensions.class);
|
|
||||||
|
|
||||||
return scanned;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,21 +1,11 @@
|
||||||
package org.gcube.smartgears.configuration.application;
|
package org.gcube.smartgears.configuration.application;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.LinkedList;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import javax.xml.bind.Unmarshaller;
|
|
||||||
import javax.xml.bind.annotation.XmlAnyElement;
|
|
||||||
import javax.xml.bind.annotation.XmlElement;
|
|
||||||
import javax.xml.bind.annotation.XmlRootElement;
|
|
||||||
|
|
||||||
import org.gcube.common.validator.ValidationError;
|
|
||||||
import org.gcube.common.validator.Validator;
|
|
||||||
import org.gcube.common.validator.ValidatorFactory;
|
|
||||||
import org.gcube.common.validator.annotations.IsValid;
|
|
||||||
import org.gcube.smartgears.handlers.application.ApplicationHandler;
|
import org.gcube.smartgears.handlers.application.ApplicationHandler;
|
||||||
import org.gcube.smartgears.handlers.application.ApplicationLifecycleHandler;
|
import org.gcube.smartgears.handlers.application.ApplicationLifecycleHandler;
|
||||||
import org.gcube.smartgears.handlers.application.RequestHandler;
|
import org.gcube.smartgears.handlers.application.RequestHandler;
|
||||||
import org.w3c.dom.Element;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The {@link ApplicationHandler}s that manage the application.
|
* The {@link ApplicationHandler}s that manage the application.
|
||||||
|
@ -23,24 +13,24 @@ import org.w3c.dom.Element;
|
||||||
* @author Fabio Simeoni
|
* @author Fabio Simeoni
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
@XmlRootElement(name="handlers")
|
|
||||||
public class ApplicationHandlers {
|
public class ApplicationHandlers {
|
||||||
|
|
||||||
|
|
||||||
@XmlElement(name="lifecycle") @IsValid
|
private List<ApplicationLifecycleHandler> lifecycleHandlers = new LinkedList<ApplicationLifecycleHandler>();
|
||||||
private LifecycleHandlers lifecycleHandlers = new LifecycleHandlers();
|
|
||||||
|
|
||||||
@XmlElement(name="request") @IsValid
|
private List<RequestHandler> requestHandlers = new LinkedList<RequestHandler>();
|
||||||
private RequestHandlers requestHandlers = new RequestHandlers();
|
|
||||||
|
|
||||||
public ApplicationHandlers() {}
|
public ApplicationHandlers(List<ApplicationLifecycleHandler> lifecycleHandlers, List<RequestHandler> requestHandlers) {
|
||||||
|
this.lifecycleHandlers = lifecycleHandlers;
|
||||||
|
this.requestHandlers = requestHandlers;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the {@link ApplicationLifecycleHandler}s for the service.
|
* Returns the {@link ApplicationLifecycleHandler}s for the service.
|
||||||
* @return the lifecycle handlers
|
* @return the lifecycle handlers
|
||||||
*/
|
*/
|
||||||
public List<ApplicationLifecycleHandler> lifecycleHandlers() {
|
public List<ApplicationLifecycleHandler> lifecycleHandlers() {
|
||||||
return lifecycleHandlers.values;
|
return lifecycleHandlers;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -48,8 +38,8 @@ public class ApplicationHandlers {
|
||||||
* @param handlers the lifecycle handlers
|
* @param handlers the lifecycle handlers
|
||||||
* @return this configuration
|
* @return this configuration
|
||||||
*/
|
*/
|
||||||
public ApplicationHandlers set(ApplicationLifecycleHandler ... handlers) {
|
public ApplicationHandlers setLifecycleHandlers(List<ApplicationLifecycleHandler> handlers) {
|
||||||
this.lifecycleHandlers = new LifecycleHandlers(Arrays.asList(handlers));
|
this.lifecycleHandlers = handlers;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,7 +48,7 @@ public class ApplicationHandlers {
|
||||||
* @return the lifetime handlers
|
* @return the lifetime handlers
|
||||||
*/
|
*/
|
||||||
public List<RequestHandler> requestHandlers() {
|
public List<RequestHandler> requestHandlers() {
|
||||||
return requestHandlers.values;
|
return requestHandlers;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -66,75 +56,11 @@ public class ApplicationHandlers {
|
||||||
* @param handlers the request handlers
|
* @param handlers the request handlers
|
||||||
* @return this configuration
|
* @return this configuration
|
||||||
*/
|
*/
|
||||||
public ApplicationHandlers set(RequestHandler ... handlers) {
|
public ApplicationHandlers setRequetHandlers(List<RequestHandler> handlers) {
|
||||||
this.requestHandlers = new RequestHandlers(Arrays.asList(handlers));
|
this.requestHandlers = handlers;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
//////////////// HELPER BINDING CLASSES
|
|
||||||
|
|
||||||
//used internally to introduce level of nesting in JAXB whilst preserving arbitrary extension
|
|
||||||
|
|
||||||
private static class LifecycleHandlers {
|
|
||||||
|
|
||||||
@SuppressWarnings("all")
|
|
||||||
LifecycleHandlers() { //needed for deserialisation
|
|
||||||
}
|
|
||||||
|
|
||||||
LifecycleHandlers(List<ApplicationLifecycleHandler> handlers) {
|
|
||||||
this.values=handlers;
|
|
||||||
}
|
|
||||||
|
|
||||||
@XmlAnyElement(lax=true)
|
|
||||||
List<ApplicationLifecycleHandler> values = new ArrayList<ApplicationLifecycleHandler>();
|
|
||||||
|
|
||||||
|
|
||||||
//since we use @AnyElement, after deserialisation, we check there are no DOM elements
|
|
||||||
@SuppressWarnings("unused")
|
|
||||||
void afterUnmarshal(Unmarshaller u, Object parent) {
|
|
||||||
for (Object o : values)
|
|
||||||
if (o instanceof Element)
|
|
||||||
throw new RuntimeException("invalid handler detected in configuration: "+Element.class.cast(o).getLocalName());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
//used internally to introduce level of nesting in JAXB whilst preserving arbitrary extension
|
|
||||||
private static class RequestHandlers {
|
|
||||||
|
|
||||||
@SuppressWarnings("all")
|
|
||||||
RequestHandlers() { //needed for deserialisation
|
|
||||||
}
|
|
||||||
|
|
||||||
RequestHandlers(List<RequestHandler> handlers) {
|
|
||||||
this.values=handlers;
|
|
||||||
}
|
|
||||||
|
|
||||||
@XmlAnyElement(lax=true)
|
|
||||||
List<RequestHandler> values = new ArrayList<RequestHandler>();
|
|
||||||
|
|
||||||
//since we use @AnyElement, after deserialisation, we check there are no DOM elements
|
|
||||||
@SuppressWarnings("unused")
|
|
||||||
void afterUnmarshal(Unmarshaller u, Object parent) {
|
|
||||||
for (Object o : values)
|
|
||||||
if (o instanceof Element)
|
|
||||||
throw new RuntimeException("invalid handler detected in configuration: "+Element.class.cast(o).getLocalName());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void mergeWith(ApplicationHandlers other){
|
public void mergeWith(ApplicationHandlers other){
|
||||||
List<ApplicationLifecycleHandler> lifecycles = other.lifecycleHandlers();
|
List<ApplicationLifecycleHandler> lifecycles = other.lifecycleHandlers();
|
||||||
|
|
|
@ -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());
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
|
@ -3,20 +3,14 @@ package org.gcube.smartgears.configuration.application;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import javax.xml.bind.annotation.XmlAccessType;
|
import org.gcube.common.validator.annotations.NotEmpty;
|
||||||
import javax.xml.bind.annotation.XmlAccessorType;
|
|
||||||
import javax.xml.bind.annotation.XmlAttribute;
|
|
||||||
import javax.xml.bind.annotation.XmlRootElement;
|
|
||||||
import javax.xml.bind.annotation.XmlValue;
|
|
||||||
|
|
||||||
@XmlRootElement(name="exclude")
|
public class GCubeExclude {
|
||||||
@XmlAccessorType(XmlAccessType.FIELD)
|
|
||||||
public class Exclude {
|
|
||||||
|
|
||||||
@XmlAttribute(name="handlers")
|
@NotEmpty
|
||||||
private List<String> handlers = new ArrayList<String>();
|
private List<String> handlers = new ArrayList<String>();
|
||||||
|
|
||||||
@XmlValue
|
@NotEmpty
|
||||||
private String path;
|
private String path;
|
||||||
|
|
||||||
public List<String> getHandlers() {
|
public List<String> getHandlers() {
|
||||||
|
@ -27,14 +21,14 @@ public class Exclude {
|
||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Exclude() {}
|
protected GCubeExclude() {}
|
||||||
|
|
||||||
public Exclude(String path) {
|
public GCubeExclude(String path) {
|
||||||
super();
|
super();
|
||||||
this.path = path;
|
this.path = path;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Exclude(List<String> handlers, String path) {
|
public GCubeExclude(List<String> handlers, String path) {
|
||||||
super();
|
super();
|
||||||
this.handlers = handlers;
|
this.handlers = handlers;
|
||||||
this.path = path;
|
this.path = path;
|
||||||
|
@ -57,7 +51,7 @@ public class Exclude {
|
||||||
return false;
|
return false;
|
||||||
if (getClass() != obj.getClass())
|
if (getClass() != obj.getClass())
|
||||||
return false;
|
return false;
|
||||||
Exclude other = (Exclude) obj;
|
GCubeExclude other = (GCubeExclude) obj;
|
||||||
if (handlers == null) {
|
if (handlers == null) {
|
||||||
if (other.handlers != null)
|
if (other.handlers != null)
|
||||||
return false;
|
return false;
|
|
@ -3,20 +3,14 @@ package org.gcube.smartgears.configuration.application;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import javax.xml.bind.annotation.XmlAccessType;
|
import org.gcube.common.validator.annotations.NotEmpty;
|
||||||
import javax.xml.bind.annotation.XmlAccessorType;
|
|
||||||
import javax.xml.bind.annotation.XmlAttribute;
|
|
||||||
import javax.xml.bind.annotation.XmlRootElement;
|
|
||||||
import javax.xml.bind.annotation.XmlValue;
|
|
||||||
|
|
||||||
@XmlRootElement(name="include")
|
public class GCubeInclude {
|
||||||
@XmlAccessorType(XmlAccessType.FIELD)
|
|
||||||
public class Include {
|
|
||||||
|
|
||||||
@XmlAttribute(name="handlers")
|
@NotEmpty
|
||||||
private List<String> handlers = new ArrayList<String>();
|
private List<String> handlers = new ArrayList<String>();
|
||||||
|
|
||||||
@XmlValue
|
@NotEmpty
|
||||||
private String path;
|
private String path;
|
||||||
|
|
||||||
public List<String> getHandlers() {
|
public List<String> getHandlers() {
|
||||||
|
@ -27,14 +21,14 @@ public class Include {
|
||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Include() {}
|
protected GCubeInclude() {}
|
||||||
|
|
||||||
public Include(String path) {
|
public GCubeInclude(String path) {
|
||||||
super();
|
super();
|
||||||
this.path = path;
|
this.path = path;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Include(List<String> handlers, String path) {
|
public GCubeInclude(List<String> handlers, String path) {
|
||||||
super();
|
super();
|
||||||
this.handlers = handlers;
|
this.handlers = handlers;
|
||||||
this.path = path;
|
this.path = path;
|
||||||
|
@ -57,7 +51,7 @@ public class Include {
|
||||||
return false;
|
return false;
|
||||||
if (getClass() != obj.getClass())
|
if (getClass() != obj.getClass())
|
||||||
return false;
|
return false;
|
||||||
Include other = (Include) obj;
|
GCubeInclude other = (GCubeInclude) obj;
|
||||||
if (handlers == null) {
|
if (handlers == null) {
|
||||||
if (other.handlers != null)
|
if (other.handlers != null)
|
||||||
return false;
|
return false;
|
|
@ -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,106 @@
|
||||||
|
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;
|
||||||
|
|
||||||
|
@NotNull @NotEmpty
|
||||||
|
private Boolean checkTokenExpiration = false;
|
||||||
|
|
||||||
|
public boolean checkTokenExpiration() {
|
||||||
|
return checkTokenExpiration;
|
||||||
|
}
|
||||||
|
|
||||||
|
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,20 +1,10 @@
|
||||||
package org.gcube.smartgears.configuration.container;
|
package org.gcube.smartgears.configuration.container;
|
||||||
|
|
||||||
import static org.gcube.smartgears.Constants.default_container_publication_frequency_in_seconds;
|
|
||||||
import static org.gcube.smartgears.utils.Utils.notNull;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
import javax.xml.bind.annotation.XmlAttribute;
|
|
||||||
import javax.xml.bind.annotation.XmlElement;
|
|
||||||
import javax.xml.bind.annotation.XmlElementRef;
|
|
||||||
import javax.xml.bind.annotation.XmlRootElement;
|
|
||||||
import javax.xml.bind.annotation.XmlTransient;
|
|
||||||
|
|
||||||
import org.gcube.common.validator.ValidationError;
|
import org.gcube.common.validator.ValidationError;
|
||||||
import org.gcube.common.validator.Validator;
|
import org.gcube.common.validator.Validator;
|
||||||
|
@ -22,11 +12,11 @@ import org.gcube.common.validator.ValidatorFactory;
|
||||||
import org.gcube.common.validator.annotations.IsValid;
|
import org.gcube.common.validator.annotations.IsValid;
|
||||||
import org.gcube.common.validator.annotations.NotEmpty;
|
import org.gcube.common.validator.annotations.NotEmpty;
|
||||||
import org.gcube.common.validator.annotations.NotNull;
|
import org.gcube.common.validator.annotations.NotNull;
|
||||||
|
import org.gcube.smartgears.configuration.AuthorizationProviderConfiguration;
|
||||||
import org.gcube.smartgears.configuration.Mode;
|
import org.gcube.smartgears.configuration.Mode;
|
||||||
|
import org.gcube.smartgears.configuration.PersistenceConfiguration;
|
||||||
|
import org.gcube.smartgears.configuration.ProxyAddress;
|
||||||
import org.gcube.smartgears.configuration.application.ApplicationConfiguration;
|
import org.gcube.smartgears.configuration.application.ApplicationConfiguration;
|
||||||
import org.gcube.smartgears.configuration.application.DefaultApplicationConfiguration;
|
|
||||||
import org.gcube.smartgears.persistence.DefaultPersistence;
|
|
||||||
import org.gcube.smartgears.persistence.Persistence;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The configuration of the container.
|
* The configuration of the container.
|
||||||
|
@ -34,76 +24,77 @@ import org.gcube.smartgears.persistence.Persistence;
|
||||||
* @author Fabio Simeoni
|
* @author Fabio Simeoni
|
||||||
* @author Luca Frosini (ISTI - CNR)
|
* @author Luca Frosini (ISTI - CNR)
|
||||||
*/
|
*/
|
||||||
@XmlRootElement(name="container")
|
|
||||||
public class ContainerConfiguration {
|
public class ContainerConfiguration {
|
||||||
|
|
||||||
|
|
||||||
@XmlAttribute
|
|
||||||
private Mode mode = Mode.online;
|
|
||||||
|
|
||||||
@XmlElement
|
|
||||||
@NotNull @IsValid
|
@NotNull @IsValid
|
||||||
String hostname;
|
private BaseConfiguration baseConfiguration;
|
||||||
|
|
||||||
@XmlElement
|
|
||||||
@NotNull
|
|
||||||
Integer port;
|
|
||||||
|
|
||||||
@XmlElement(name ="authentication-endpoint")
|
|
||||||
String authenticationEnpoint = null;
|
|
||||||
|
|
||||||
@XmlElement(name ="protocol")
|
|
||||||
@NotNull @IsValid
|
|
||||||
String protocol="http";
|
|
||||||
|
|
||||||
@XmlElement
|
|
||||||
boolean authorizeChildrenContext = false;
|
|
||||||
|
|
||||||
@XmlElement
|
|
||||||
@NotNull@IsValid
|
|
||||||
String infrastructure;
|
|
||||||
|
|
||||||
@XmlElement
|
|
||||||
@NotNull @IsValid
|
|
||||||
Site site;
|
|
||||||
|
|
||||||
@XmlElement(name="token")
|
|
||||||
@NotNull @NotEmpty
|
|
||||||
List<String> tokens = new ArrayList<String>();
|
|
||||||
|
|
||||||
@XmlTransient
|
|
||||||
Set<String> allowedContext = new HashSet<String>();
|
|
||||||
|
|
||||||
@XmlElementRef(type=DefaultApplicationConfiguration.class)
|
|
||||||
List<ApplicationConfiguration> apps = new ArrayList<ApplicationConfiguration>();
|
|
||||||
|
|
||||||
@XmlElement(name="property")
|
|
||||||
@IsValid
|
@IsValid
|
||||||
List<Property> properties = new ArrayList<Property>();
|
private Map<String,String> properties = new HashMap<String, String>();
|
||||||
|
|
||||||
@XmlElement(name="publication-frequency")
|
@NotNull @IsValid
|
||||||
long publicationFrequency = default_container_publication_frequency_in_seconds;
|
private Site site;
|
||||||
|
|
||||||
@XmlElementRef(type=DefaultPersistence.class)
|
|
||||||
@IsValid
|
@IsValid
|
||||||
private Persistence persistenceManager;
|
private ProxyAddress proxy;
|
||||||
|
|
||||||
|
@NotEmpty @NotNull
|
||||||
|
private String accountingFallbackLocation;
|
||||||
|
|
||||||
|
private List<ApplicationConfiguration> apps = new ArrayList<ApplicationConfiguration>();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@NotNull @IsValid
|
||||||
|
private PersistenceConfiguration persistenceConfiguration;
|
||||||
|
|
||||||
|
@NotNull @IsValid
|
||||||
|
private AuthorizationProviderConfiguration authorizationConfiguration;
|
||||||
|
|
||||||
|
|
||||||
|
protected void setBaseConfiguration(BaseConfiguration baseConfiguration) {
|
||||||
|
this.baseConfiguration = baseConfiguration;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void setProperties(Map<String, String> properties) {
|
||||||
|
this.properties = properties;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void setSite(Site site) {
|
||||||
|
this.site = site;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void setProxy(ProxyAddress proxy) {
|
||||||
|
this.proxy = proxy;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void setAccountingFallbackLocation(String accountingFallbackLocation) {
|
||||||
|
this.accountingFallbackLocation = accountingFallbackLocation;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void setPersistenceConfiguration(PersistenceConfiguration persistenceConfiguration) {
|
||||||
|
this.persistenceConfiguration = persistenceConfiguration;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void setAuthorizationProviderConfiguration(
|
||||||
|
AuthorizationProviderConfiguration authorizationConfiguration) {
|
||||||
|
this.authorizationConfiguration = authorizationConfiguration;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setApps(List<ApplicationConfiguration> apps) {
|
||||||
|
this.apps = apps;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the management mode for the container.
|
* Returns the management mode for the container.
|
||||||
* @return the management mode
|
* @return the management mode
|
||||||
*/
|
*/
|
||||||
public Mode mode() {
|
public Mode mode() {
|
||||||
return mode;
|
return baseConfiguration.getMode();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public boolean checkTokenExpiration() {
|
||||||
* Sets the management mode for the container.
|
return baseConfiguration.checkTokenExpiration();
|
||||||
* @param mode the management mode
|
|
||||||
* @return this configuration
|
|
||||||
*/
|
|
||||||
public ContainerConfiguration mode(Mode mode) {
|
|
||||||
this.mode=mode;
|
|
||||||
return this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -155,52 +146,22 @@ public class ContainerConfiguration {
|
||||||
return site;
|
return site;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the geographical site of the container.
|
|
||||||
* @param site the site
|
|
||||||
* @return this configuration
|
|
||||||
*/
|
|
||||||
public ContainerConfiguration site(Site site) {
|
|
||||||
this.site=site;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the infrastructure in which the container is running.
|
* Returns the infrastructure in which the container is running.
|
||||||
* @return the infrastructure
|
* @return the infrastructure
|
||||||
*/
|
*/
|
||||||
public String infrastructure() {
|
public String infrastructure() {
|
||||||
return infrastructure;
|
return baseConfiguration.getInfrastructure();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the infrastructure in which the container is running.
|
|
||||||
* @param infrastructure the infrastructure
|
|
||||||
* @return this configuration
|
|
||||||
*/
|
|
||||||
public ContainerConfiguration infrastructure(String infrastructure) {
|
|
||||||
this.infrastructure=infrastructure;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the host name of the container.
|
* Returns the host name of the container.
|
||||||
* @return the host name;
|
* @return the host name;
|
||||||
*/
|
*/
|
||||||
public String hostname() {
|
public String hostname() {
|
||||||
return hostname;
|
return baseConfiguration.getHostname();
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the host name of the container.
|
|
||||||
* @param name the host name
|
|
||||||
* @return this configuration
|
|
||||||
*/
|
|
||||||
public ContainerConfiguration hostname(String name) {
|
|
||||||
this.hostname=name;
|
|
||||||
return this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -208,7 +169,7 @@ public class ContainerConfiguration {
|
||||||
* @return the port
|
* @return the port
|
||||||
*/
|
*/
|
||||||
public int port() {
|
public int port() {
|
||||||
return port;
|
return baseConfiguration.getPort();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -217,81 +178,45 @@ public class ContainerConfiguration {
|
||||||
* @return the port
|
* @return the port
|
||||||
*/
|
*/
|
||||||
public String protocol() {
|
public String protocol() {
|
||||||
return protocol;
|
return baseConfiguration.getProtocol();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public String authenticationEnpoint() {
|
|
||||||
return authenticationEnpoint;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ContainerConfiguration authenticationEnpoint(String endpoint) {
|
|
||||||
this.authenticationEnpoint = endpoint;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the port at which the container is listening for requests.
|
|
||||||
* @param port the port
|
|
||||||
* @return this configuration
|
|
||||||
*/
|
|
||||||
public ContainerConfiguration port(int port) {
|
|
||||||
this.port=port;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ContainerConfiguration protocol(String protocol) {
|
|
||||||
this.protocol=protocol;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean authorizeChildrenContext() {
|
public boolean authorizeChildrenContext() {
|
||||||
return authorizeChildrenContext;
|
return baseConfiguration.isAuthorizeChildrenContext();
|
||||||
}
|
|
||||||
|
|
||||||
public ContainerConfiguration authorizeChildrenContext(boolean authorizeChildrenContext) {
|
|
||||||
this.authorizeChildrenContext = authorizeChildrenContext;
|
|
||||||
return this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the VOs in which the container initially operates.
|
* Returns the proxy of the container.
|
||||||
* @return the VOs
|
* @return the proxy
|
||||||
*/
|
*/
|
||||||
public List<String> startTokens() {
|
public ProxyAddress proxy() {
|
||||||
return tokens;
|
return proxy;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the VOs in which the container initially operates.
|
* Returns the persistence manager of the container.
|
||||||
* @param vos the VOs
|
* @return the manager
|
||||||
* @return this configuration
|
|
||||||
*/
|
*/
|
||||||
public ContainerConfiguration startTokens(List<String> tokens) {
|
public PersistenceConfiguration persistenceConfiguration() {
|
||||||
|
return this.persistenceConfiguration;
|
||||||
notNull("start Tokens",tokens);
|
|
||||||
|
|
||||||
this.tokens = tokens;
|
|
||||||
|
|
||||||
return this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the persistence manager of the container.
|
* Returns the persistence manager of the container.
|
||||||
* @return the manager
|
* @return the manager
|
||||||
*/
|
*/
|
||||||
public Persistence persistence() {
|
public String accountingFallbackLocation() {
|
||||||
return persistenceManager;
|
return accountingFallbackLocation;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the persistence manager of the container.
|
* Returns the authorization configuration.
|
||||||
* @param manager the manager
|
* @return AuthorizationProviderConfiguration the configuration
|
||||||
* @return this configuration
|
|
||||||
*/
|
*/
|
||||||
public ContainerConfiguration persistence(Persistence manager) {
|
public AuthorizationProviderConfiguration authorizationConfiguration() {
|
||||||
this.persistenceManager=manager;
|
return authorizationConfiguration;
|
||||||
return this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -299,21 +224,7 @@ public class ContainerConfiguration {
|
||||||
* @return the properties
|
* @return the properties
|
||||||
*/
|
*/
|
||||||
public Map<String,String> properties() {
|
public Map<String,String> properties() {
|
||||||
Map<String,String> map = new HashMap<String, String>();
|
return Collections.unmodifiableMap(properties);
|
||||||
for (Property prop : properties)
|
|
||||||
map.put(prop.name, prop.value);
|
|
||||||
return map;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds a configuration property to the container.
|
|
||||||
* @param the name of the property
|
|
||||||
* @param the value of the property
|
|
||||||
* @return this configuration
|
|
||||||
*/
|
|
||||||
public ContainerConfiguration property(String name, String value) {
|
|
||||||
properties.add(new Property(name, value));
|
|
||||||
return this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -321,26 +232,7 @@ public class ContainerConfiguration {
|
||||||
* @return the frquency;
|
* @return the frquency;
|
||||||
*/
|
*/
|
||||||
public long publicationFrequency() {
|
public long publicationFrequency() {
|
||||||
return publicationFrequency;
|
return baseConfiguration.getPublicationFrequencyInSeconds();
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the publication frequency for the container's profile.
|
|
||||||
* @param frequency the frequency
|
|
||||||
* @return this configuration
|
|
||||||
*/
|
|
||||||
public ContainerConfiguration publicationFrequency(long frequency) {
|
|
||||||
this.publicationFrequency=frequency;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public Set<String> allowedContexts() {
|
|
||||||
return allowedContext;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void allowedContexts(Set<String> allowedContexts) {
|
|
||||||
this.allowedContext = allowedContexts;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -362,159 +254,14 @@ public class ContainerConfiguration {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static class Property {
|
|
||||||
|
|
||||||
@XmlAttribute @NotNull
|
|
||||||
String name;
|
|
||||||
|
|
||||||
@XmlAttribute @NotNull
|
|
||||||
String value;
|
|
||||||
|
|
||||||
Property() {}
|
|
||||||
|
|
||||||
Property(String key, String value) {
|
|
||||||
this.name=key;
|
|
||||||
this.value=value;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int hashCode() {
|
|
||||||
final int prime = 31;
|
|
||||||
int result = 1;
|
|
||||||
result = prime * result + ((name == null) ? 0 : name.hashCode());
|
|
||||||
result = prime * result + ((value == null) ? 0 : value.hashCode());
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean equals(Object obj) {
|
|
||||||
if (this == obj)
|
|
||||||
return true;
|
|
||||||
if (obj == null)
|
|
||||||
return false;
|
|
||||||
if (getClass() != obj.getClass())
|
|
||||||
return false;
|
|
||||||
Property other = (Property) obj;
|
|
||||||
if (name == null) {
|
|
||||||
if (other.name != null)
|
|
||||||
return false;
|
|
||||||
} else if (!name.equals(other.name))
|
|
||||||
return false;
|
|
||||||
if (value == null) {
|
|
||||||
if (other.value != null)
|
|
||||||
return false;
|
|
||||||
} else if (!value.equals(other.value))
|
|
||||||
return false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int hashCode() {
|
|
||||||
final int prime = 31;
|
|
||||||
int result = 1;
|
|
||||||
result = prime * result + ((allowedContext == null) ? 0 : allowedContext.hashCode());
|
|
||||||
result = prime * result + ((apps == null) ? 0 : apps.hashCode());
|
|
||||||
result = prime * result + ((authenticationEnpoint == null) ? 0 : authenticationEnpoint.hashCode());
|
|
||||||
result = prime * result + (authorizeChildrenContext ? 1231 : 1237);
|
|
||||||
result = prime * result + ((hostname == null) ? 0 : hostname.hashCode());
|
|
||||||
result = prime * result + ((infrastructure == null) ? 0 : infrastructure.hashCode());
|
|
||||||
result = prime * result + ((mode == null) ? 0 : mode.hashCode());
|
|
||||||
result = prime * result + ((persistenceManager == null) ? 0 : persistenceManager.hashCode());
|
|
||||||
result = prime * result + ((port == null) ? 0 : port.hashCode());
|
|
||||||
result = prime * result + ((properties == null) ? 0 : properties.hashCode());
|
|
||||||
result = prime * result + ((protocol == null) ? 0 : protocol.hashCode());
|
|
||||||
result = prime * result + (int) (publicationFrequency ^ (publicationFrequency >>> 32));
|
|
||||||
result = prime * result + ((site == null) ? 0 : site.hashCode());
|
|
||||||
result = prime * result + ((tokens == null) ? 0 : tokens.hashCode());
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean equals(Object obj) {
|
|
||||||
if (this == obj)
|
|
||||||
return true;
|
|
||||||
if (obj == null)
|
|
||||||
return false;
|
|
||||||
if (getClass() != obj.getClass())
|
|
||||||
return false;
|
|
||||||
ContainerConfiguration other = (ContainerConfiguration) obj;
|
|
||||||
if (allowedContext == null) {
|
|
||||||
if (other.allowedContext != null)
|
|
||||||
return false;
|
|
||||||
} else if (!allowedContext.equals(other.allowedContext))
|
|
||||||
return false;
|
|
||||||
if (apps == null) {
|
|
||||||
if (other.apps != null)
|
|
||||||
return false;
|
|
||||||
} else if (!apps.equals(other.apps))
|
|
||||||
return false;
|
|
||||||
if (authenticationEnpoint == null) {
|
|
||||||
if (other.authenticationEnpoint != null)
|
|
||||||
return false;
|
|
||||||
} else if (!authenticationEnpoint.equals(other.authenticationEnpoint))
|
|
||||||
return false;
|
|
||||||
if (authorizeChildrenContext != other.authorizeChildrenContext)
|
|
||||||
return false;
|
|
||||||
if (hostname == null) {
|
|
||||||
if (other.hostname != null)
|
|
||||||
return false;
|
|
||||||
} else if (!hostname.equals(other.hostname))
|
|
||||||
return false;
|
|
||||||
if (infrastructure == null) {
|
|
||||||
if (other.infrastructure != null)
|
|
||||||
return false;
|
|
||||||
} else if (!infrastructure.equals(other.infrastructure))
|
|
||||||
return false;
|
|
||||||
if (mode != other.mode)
|
|
||||||
return false;
|
|
||||||
if (persistenceManager == null) {
|
|
||||||
if (other.persistenceManager != null)
|
|
||||||
return false;
|
|
||||||
} else if (!persistenceManager.equals(other.persistenceManager))
|
|
||||||
return false;
|
|
||||||
if (port == null) {
|
|
||||||
if (other.port != null)
|
|
||||||
return false;
|
|
||||||
} else if (!port.equals(other.port))
|
|
||||||
return false;
|
|
||||||
if (properties == null) {
|
|
||||||
if (other.properties != null)
|
|
||||||
return false;
|
|
||||||
} else if (!properties.equals(other.properties))
|
|
||||||
return false;
|
|
||||||
if (protocol == null) {
|
|
||||||
if (other.protocol != null)
|
|
||||||
return false;
|
|
||||||
} else if (!protocol.equals(other.protocol))
|
|
||||||
return false;
|
|
||||||
if (publicationFrequency != other.publicationFrequency)
|
|
||||||
return false;
|
|
||||||
if (site == null) {
|
|
||||||
if (other.site != null)
|
|
||||||
return false;
|
|
||||||
} else if (!site.equals(other.site))
|
|
||||||
return false;
|
|
||||||
if (tokens == null) {
|
|
||||||
if (other.tokens != null)
|
|
||||||
return false;
|
|
||||||
} else if (!tokens.equals(other.tokens))
|
|
||||||
return false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "ContainerConfiguration [mode=" + mode + ", hostname=" + hostname + ", port=" + port + ", authenticationEnpoint=" + authenticationEnpoint + ", protocol=" + protocol
|
return "ContainerConfiguration [baseConfiguration=" + baseConfiguration + ", properties=" + properties
|
||||||
+ ", authorizeChildrenContext=" + authorizeChildrenContext + ", infrastructure=" + infrastructure
|
+ ", site=" + site + ", proxy=" + proxy + ", accountingFallbackLocation=" + accountingFallbackLocation
|
||||||
+ ", site=" + site + ", tokens=" + tokens + ", allowedContext=" + allowedContext + ", apps=" + apps
|
+ ", persistence=" + persistenceConfiguration.getImplementationClass().getSimpleName()
|
||||||
+ ", properties=" + properties + ", publicationFrequency=" + publicationFrequency
|
+ ", authorizationProvider=" + authorizationConfiguration + "]";
|
||||||
+ ", persistenceManager=" + persistenceManager + "]";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
|
@ -1,18 +1,31 @@
|
||||||
package org.gcube.smartgears.configuration.container;
|
package org.gcube.smartgears.configuration.container;
|
||||||
|
|
||||||
import static org.gcube.smartgears.utils.Utils.*;
|
import java.io.File;
|
||||||
|
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.lang.reflect.Modifier;
|
import java.util.Collections;
|
||||||
import java.util.HashSet;
|
import java.util.LinkedList;
|
||||||
import java.util.ServiceLoader;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Map.Entry;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
import javax.xml.bind.JAXBContext;
|
|
||||||
import javax.xml.bind.JAXBException;
|
|
||||||
|
|
||||||
|
import org.gcube.common.security.credentials.Credentials;
|
||||||
|
import org.gcube.common.security.factories.AuthorizationProviderFactory;
|
||||||
|
import org.gcube.smartgears.configuration.AuthorizationProviderConfiguration;
|
||||||
|
import org.gcube.smartgears.configuration.ComponentConfiguration;
|
||||||
|
import org.gcube.smartgears.configuration.ConfiguredWith;
|
||||||
|
import org.gcube.smartgears.configuration.PersistenceConfiguration;
|
||||||
|
import org.gcube.smartgears.configuration.ProxyAddress;
|
||||||
|
import org.gcube.smartgears.configuration.SmartgearsConfiguration;
|
||||||
import org.gcube.smartgears.handlers.container.ContainerHandler;
|
import org.gcube.smartgears.handlers.container.ContainerHandler;
|
||||||
|
import org.gcube.smartgears.handlers.container.lifecycle.AccountingManager;
|
||||||
|
import org.gcube.smartgears.handlers.container.lifecycle.ContainerProfileManager;
|
||||||
|
import org.gcube.smartgears.persistence.LocalWriter;
|
||||||
|
import org.gcube.smartgears.persistence.LocalWriterConfiguration;
|
||||||
|
import org.gcube.smartgears.persistence.PersistenceWriter;
|
||||||
|
import org.gcube.smartgears.security.defaults.DefaultAuthorizationProviderFactory;
|
||||||
import org.gcube.smartgears.utils.Utils;
|
import org.gcube.smartgears.utils.Utils;
|
||||||
|
import org.ini4j.Ini;
|
||||||
|
import org.ini4j.Profile.Section;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Binds {@link ContainerConfiguration}s to and from XML serialisations.
|
* Binds {@link ContainerConfiguration}s to and from XML serialisations.
|
||||||
|
@ -22,31 +35,135 @@ import org.gcube.smartgears.utils.Utils;
|
||||||
*/
|
*/
|
||||||
public class ContainerConfigurationBinder {
|
public class ContainerConfigurationBinder {
|
||||||
|
|
||||||
/**
|
public ContainerConfiguration load(InputStream stream) {
|
||||||
* Returns a {@link ContainerConfiguration} from its XML serialisation.
|
|
||||||
*
|
|
||||||
* @param stream the serialisation
|
|
||||||
* @return the configuration
|
|
||||||
* @throws RuntimeException if the serialisation is invalid
|
|
||||||
*/
|
|
||||||
public ContainerConfiguration bind(InputStream stream) {
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
Ini configurator = new Ini(stream);
|
||||||
|
ContainerConfiguration conf = new ContainerConfiguration();
|
||||||
|
|
||||||
JAXBContext ctx = JAXBContext.newInstance(ContainerConfiguration.class);
|
Section nodeSection = configurator.get("node");
|
||||||
|
if (nodeSection != null) {
|
||||||
|
BaseConfiguration nodeConf = new BaseConfiguration();
|
||||||
|
nodeSection.to(nodeConf);
|
||||||
|
conf.setBaseConfiguration(nodeConf);
|
||||||
|
}
|
||||||
|
|
||||||
ContainerConfiguration config = (ContainerConfiguration) ctx.createUnmarshaller().unmarshal(stream);
|
Section propertiesSection = configurator.get("properties");
|
||||||
|
if (propertiesSection != null)
|
||||||
|
conf.setProperties(propertiesSection.entrySet().stream()
|
||||||
|
.collect(Collectors.toMap(Entry::getKey, Entry::getValue)));
|
||||||
|
|
||||||
return config;
|
Section siteSection = configurator.get("site");
|
||||||
|
if (siteSection != null) {
|
||||||
|
Site siteConf = new Site();
|
||||||
|
siteSection.to(siteConf);
|
||||||
|
conf.setSite(siteConf);
|
||||||
|
}
|
||||||
|
|
||||||
} catch (JAXBException e) {
|
initAuthorizationPart(configurator, conf);
|
||||||
|
|
||||||
throw new RuntimeException("invalid container configuration", e);
|
initPersistencePart(configurator, conf);
|
||||||
|
|
||||||
|
initProxyPart(configurator, conf);
|
||||||
|
|
||||||
|
// TODO: find a solution for this shit
|
||||||
|
String location = Utils.home() + "/state";
|
||||||
|
File dir = new File(location);
|
||||||
|
if (!dir.exists())
|
||||||
|
dir.mkdirs();
|
||||||
|
conf.setAccountingFallbackLocation(location);
|
||||||
|
// END Shit
|
||||||
|
|
||||||
|
return conf;
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initProxyPart(Ini configurator, ContainerConfiguration conf) throws Exception {
|
||||||
|
Section proxySection = configurator.get("proxy");
|
||||||
|
if (proxySection != null) {
|
||||||
|
ProxyAddress proxyConf = new ProxyAddress();
|
||||||
|
proxySection.to(proxyConf);
|
||||||
|
conf.setProxy(proxyConf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
private void initPersistencePart(Ini configurator, ContainerConfiguration conf) throws Exception {
|
||||||
|
Section persistenceSection = configurator.get("persistence");
|
||||||
|
if (persistenceSection != null) {
|
||||||
|
String type = persistenceSection.get("class");
|
||||||
|
if (type == null)
|
||||||
|
throw new Exception("ini file error: type not found in \"persistence\" section");
|
||||||
|
/*
|
||||||
|
* PersistenceWriter persistenceWriter; try { Object persistenceImpl =
|
||||||
|
* Class.forName(type).getDeclaredConstructor().newInstance(); persistenceWriter
|
||||||
|
* = PersistenceWriter.class.cast(persistenceImpl); }catch (Exception e) { throw
|
||||||
|
* new
|
||||||
|
* Exception("ini file error: invalid persistence type in \"persistence\" section"
|
||||||
|
* , e); }
|
||||||
|
*/
|
||||||
|
// persistenceSection.to(persistenceWriter);
|
||||||
|
|
||||||
|
Class<? extends PersistenceWriter> persistenceClass = null;
|
||||||
|
try {
|
||||||
|
persistenceClass = (Class<? extends PersistenceWriter>) Class.forName(type);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new Exception("ini file error: invalid persistence type in \"persistence\" section", e);
|
||||||
|
}
|
||||||
|
if (!persistenceClass.isAnnotationPresent(ConfiguredWith.class))
|
||||||
|
throw new Exception(
|
||||||
|
"ini file error: invalid class type in \"persistence\" section,ConfiguredWith annotation not present");
|
||||||
|
Class<? extends ComponentConfiguration> writerConfClass = persistenceClass
|
||||||
|
.getAnnotation(ConfiguredWith.class).value();
|
||||||
|
ComponentConfiguration writerConfiguration = writerConfClass.getDeclaredConstructor().newInstance();
|
||||||
|
persistenceSection.to(writerConfiguration, ".");
|
||||||
|
conf.setPersistenceConfiguration(
|
||||||
|
new PersistenceConfiguration((Class<PersistenceWriter>) persistenceClass, writerConfiguration));
|
||||||
|
} else {
|
||||||
|
String location = Utils.home() + "/state";
|
||||||
|
File dir = new File(location);
|
||||||
|
if (!dir.exists())
|
||||||
|
dir.mkdirs();
|
||||||
|
|
||||||
|
conf.setPersistenceConfiguration(
|
||||||
|
new PersistenceConfiguration(LocalWriter.class, new LocalWriterConfiguration(location)));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
finally {
|
|
||||||
|
|
||||||
Utils.closeSafely(stream);
|
private void initAuthorizationPart(Ini configurator, ContainerConfiguration conf) throws Exception {
|
||||||
|
Section authorizationSection = configurator.get("authorization");
|
||||||
|
if (authorizationSection != null) {
|
||||||
|
|
||||||
|
String provider = authorizationSection.get("factory");
|
||||||
|
AuthorizationProviderFactory<?> authProviderFactory;
|
||||||
|
if (provider != null) {
|
||||||
|
try {
|
||||||
|
Object authProviderImpl = Class.forName(provider).getDeclaredConstructor().newInstance();
|
||||||
|
authProviderFactory = AuthorizationProviderFactory.class.cast(authProviderImpl);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new Exception("ini file error: invalid provider type in \"authorization\" section", e);
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
authProviderFactory = new DefaultAuthorizationProviderFactory();
|
||||||
|
|
||||||
|
authorizationSection.to(authProviderFactory, "factory.");
|
||||||
|
|
||||||
|
String type = authorizationSection.get("credentials.class");
|
||||||
|
if (type == null)
|
||||||
|
throw new Exception("ini file error: credentials type not found in \"authorization\" section");
|
||||||
|
Credentials credentials;
|
||||||
|
try {
|
||||||
|
Object credentialsImpl = Class.forName(type).getDeclaredConstructor().newInstance();
|
||||||
|
credentials = Credentials.class.cast(credentialsImpl);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new Exception("ini file error: invalid credentials type in \"authorization\" section", e);
|
||||||
|
}
|
||||||
|
authorizationSection.to(credentials, "credentials.");
|
||||||
|
|
||||||
|
conf.setAuthorizationProviderConfiguration(
|
||||||
|
new AuthorizationProviderConfiguration(authProviderFactory, credentials));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -57,45 +174,35 @@ public class ContainerConfigurationBinder {
|
||||||
* @return the handlers
|
* @return the handlers
|
||||||
* @throws RuntimeException if the serialisation is invalid
|
* @throws RuntimeException if the serialisation is invalid
|
||||||
*/
|
*/
|
||||||
public ContainerHandlers bindHandlers(InputStream stream) {
|
public List<ContainerHandler> bindHandlers(ClassLoader classloader) {
|
||||||
|
|
||||||
//collects handler classes
|
LinkedList<ContainerHandler> handlers = new LinkedList<ContainerHandler>();
|
||||||
Set<Class<?>> classes = scanForConfigurationElements();
|
|
||||||
|
|
||||||
|
// ADDING BASE Handlers (order is important)
|
||||||
|
handlers.add(new AccountingManager());
|
||||||
|
handlers.add(new ContainerProfileManager());
|
||||||
|
|
||||||
|
handlers.addAll(scanForContainerHadlers(classloader));
|
||||||
|
|
||||||
|
return handlers;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<? extends ContainerHandler> scanForContainerHadlers(ClassLoader classloader) throws RuntimeException {
|
||||||
|
|
||||||
|
// TODO: scan for Container Handler
|
||||||
|
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
public SmartgearsConfiguration loadSmartgearsProperty() {
|
||||||
try {
|
try {
|
||||||
|
Ini configurator = new Ini(this.getClass().getResourceAsStream("/META-INF/smartgears-config.ini"));
|
||||||
JAXBContext ctx = JAXBContext.newInstance(classes.toArray(new Class<?>[0]));
|
String version = configurator.get("smartgears").get("version");
|
||||||
|
return new SmartgearsConfiguration(version);
|
||||||
return (ContainerHandlers) ctx.createUnmarshaller().unmarshal(stream);
|
}catch (Exception e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
} catch (JAXBException e) {
|
|
||||||
|
|
||||||
throw unchecked(e);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private Set<Class<?>> scanForConfigurationElements() throws RuntimeException {
|
|
||||||
|
|
||||||
@SuppressWarnings("all")
|
|
||||||
ServiceLoader<ContainerHandler> handlerLoader = (ServiceLoader) ServiceLoader.load(ContainerHandler.class);
|
|
||||||
|
|
||||||
Set<Class<?>> scanned = new HashSet<Class<?>>();
|
|
||||||
|
|
||||||
for (ContainerHandler handler : handlerLoader) {
|
|
||||||
Class<?> handlerClass = handler.getClass();
|
|
||||||
if (handlerClass.isInterface() || handlerClass.getModifiers() == Modifier.ABSTRACT)
|
|
||||||
continue;
|
|
||||||
else
|
|
||||||
scanned.add(handlerClass);
|
|
||||||
}
|
|
||||||
|
|
||||||
//add top-level configuration
|
|
||||||
scanned.add(ContainerHandlers.class);
|
|
||||||
|
|
||||||
return scanned;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,8 +1,5 @@
|
||||||
package org.gcube.smartgears.configuration.container;
|
package org.gcube.smartgears.configuration.container;
|
||||||
|
|
||||||
import javax.xml.bind.annotation.XmlElement;
|
|
||||||
import javax.xml.bind.annotation.XmlRootElement;
|
|
||||||
|
|
||||||
import org.gcube.common.validator.annotations.NotNull;
|
import org.gcube.common.validator.annotations.NotNull;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -11,97 +8,28 @@ import org.gcube.common.validator.annotations.NotNull;
|
||||||
* @author Fabio Simeoni
|
* @author Fabio Simeoni
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
@XmlRootElement(name="site")
|
|
||||||
public class Site {
|
public class Site {
|
||||||
|
|
||||||
@XmlElement
|
|
||||||
@NotNull
|
@NotNull
|
||||||
String country;
|
String country;
|
||||||
|
|
||||||
@XmlElement
|
|
||||||
@NotNull
|
@NotNull
|
||||||
String location;
|
String location;
|
||||||
|
|
||||||
@XmlElement
|
public String getCountry() {
|
||||||
@NotNull
|
|
||||||
String latitude;
|
|
||||||
|
|
||||||
@XmlElement
|
|
||||||
@NotNull
|
|
||||||
String longitude;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the country.
|
|
||||||
* @return the country
|
|
||||||
*/
|
|
||||||
public String country() {
|
|
||||||
return country;
|
return country;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public void setCountry(String country) {
|
||||||
* Sets the country.
|
|
||||||
* @param the country
|
|
||||||
* @return this configuration
|
|
||||||
*/
|
|
||||||
public Site country(String country) {
|
|
||||||
this.country = country;
|
this.country = country;
|
||||||
return this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getLocation() {
|
||||||
/**
|
|
||||||
* Returns the latitude.
|
|
||||||
* @return the latitude
|
|
||||||
*/
|
|
||||||
public String latitude() {
|
|
||||||
return latitude;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the latitude.
|
|
||||||
* @param the latitude
|
|
||||||
* @return this configuration
|
|
||||||
*/
|
|
||||||
public Site latitude(String latitude) {
|
|
||||||
this.latitude=latitude;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the longitude.
|
|
||||||
* @return the longitude
|
|
||||||
*/
|
|
||||||
public String longitude() {
|
|
||||||
return longitude;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the longitude.
|
|
||||||
* @param the longitude
|
|
||||||
* @return this configuration
|
|
||||||
*/
|
|
||||||
public Site longitude(String longitude) {
|
|
||||||
this.longitude=longitude;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the location.
|
|
||||||
* @return the location
|
|
||||||
*/
|
|
||||||
public String location() {
|
|
||||||
return location;
|
return location;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public void setLocation(String location) {
|
||||||
* Sets the location.
|
|
||||||
* @param the location
|
|
||||||
* @return this location
|
|
||||||
*/
|
|
||||||
public Site location(String location) {
|
|
||||||
this.location = location;
|
this.location = location;
|
||||||
return this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -109,9 +37,7 @@ public class Site {
|
||||||
final int prime = 31;
|
final int prime = 31;
|
||||||
int result = 1;
|
int result = 1;
|
||||||
result = prime * result + ((country == null) ? 0 : country.hashCode());
|
result = prime * result + ((country == null) ? 0 : country.hashCode());
|
||||||
result = prime * result + ((latitude == null) ? 0 : latitude.hashCode());
|
|
||||||
result = prime * result + ((location == null) ? 0 : location.hashCode());
|
result = prime * result + ((location == null) ? 0 : location.hashCode());
|
||||||
result = prime * result + ((longitude == null) ? 0 : longitude.hashCode());
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -129,24 +55,12 @@ public class Site {
|
||||||
return false;
|
return false;
|
||||||
} else if (!country.equals(other.country))
|
} else if (!country.equals(other.country))
|
||||||
return false;
|
return false;
|
||||||
if (latitude == null) {
|
|
||||||
if (other.latitude != null)
|
|
||||||
return false;
|
|
||||||
} else if (!latitude.equals(other.latitude))
|
|
||||||
return false;
|
|
||||||
if (location == null) {
|
if (location == null) {
|
||||||
if (other.location != null)
|
if (other.location != null)
|
||||||
return false;
|
return false;
|
||||||
} else if (!location.equals(other.location))
|
} else if (!location.equals(other.location))
|
||||||
return false;
|
return false;
|
||||||
if (longitude == null) {
|
|
||||||
if (other.longitude != null)
|
|
||||||
return false;
|
|
||||||
} else if (!longitude.equals(other.longitude))
|
|
||||||
return false;
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,13 +1,19 @@
|
||||||
package org.gcube.smartgears.context.application;
|
package org.gcube.smartgears.context.application;
|
||||||
|
|
||||||
import javax.servlet.ServletContext;
|
import java.nio.file.Path;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import org.gcube.common.events.Hub;
|
import org.gcube.common.events.Hub;
|
||||||
|
import org.gcube.common.security.factories.AuthorizationProvider;
|
||||||
|
import org.gcube.common.security.secrets.Secret;
|
||||||
import org.gcube.smartgears.configuration.application.ApplicationConfiguration;
|
import org.gcube.smartgears.configuration.application.ApplicationConfiguration;
|
||||||
import org.gcube.smartgears.context.Properties;
|
import org.gcube.smartgears.context.Properties;
|
||||||
import org.gcube.smartgears.context.container.ContainerContext;
|
import org.gcube.smartgears.context.container.ContainerContext;
|
||||||
import org.gcube.smartgears.lifecycle.application.ApplicationLifecycle;
|
import org.gcube.smartgears.lifecycle.application.ApplicationLifecycle;
|
||||||
import org.gcube.smartgears.persistence.Persistence;
|
import org.gcube.smartgears.persistence.PersistenceWriter;
|
||||||
|
import org.gcube.smartgears.security.secrets.SecretFactory;
|
||||||
|
|
||||||
|
import jakarta.servlet.ServletContext;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The management context of an application.
|
* The management context of an application.
|
||||||
|
@ -34,9 +40,6 @@ public interface ApplicationContext {
|
||||||
*/
|
*/
|
||||||
ApplicationConfiguration configuration();
|
ApplicationConfiguration configuration();
|
||||||
|
|
||||||
|
|
||||||
<T> T profile(Class<T> type);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the lifecycle of the application.
|
* Returns the lifecycle of the application.
|
||||||
*
|
*
|
||||||
|
@ -56,7 +59,7 @@ public interface ApplicationContext {
|
||||||
*
|
*
|
||||||
* @return the manager
|
* @return the manager
|
||||||
*/
|
*/
|
||||||
Persistence persistence();
|
PersistenceWriter persistence();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the servlet context of the application.
|
* Returns the servlet context of the application.
|
||||||
|
@ -79,4 +82,24 @@ public interface ApplicationContext {
|
||||||
*/
|
*/
|
||||||
Properties properties();
|
Properties properties();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the authorization provider.
|
||||||
|
* @return the AuhtorizationProvider
|
||||||
|
**/
|
||||||
|
AuthorizationProvider authorizationProvider();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the Path to the configuration Folder for the current app
|
||||||
|
*
|
||||||
|
* @return the Path to the folder , null if the Path is not present
|
||||||
|
*/
|
||||||
|
Path appSpecificConfigurationFolder();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns the list of factory secrets ordered by priority
|
||||||
|
*
|
||||||
|
* @returnA Linked List
|
||||||
|
*/
|
||||||
|
List<SecretFactory<? extends Secret>> allowedSecretFactories();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,16 +1,35 @@
|
||||||
package org.gcube.smartgears.context.application;
|
package org.gcube.smartgears.context.application;
|
||||||
|
|
||||||
import static org.gcube.smartgears.Constants.profile_property;
|
import static org.gcube.smartgears.Constants.profile_file_path;
|
||||||
|
|
||||||
import javax.servlet.ServletContext;
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.ObjectInputStream;
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.Paths;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
import org.gcube.common.events.Hub;
|
import org.gcube.common.events.Hub;
|
||||||
import org.gcube.common.resources.gcore.GCoreEndpoint;
|
import org.gcube.common.security.factories.AuthorizationProvider;
|
||||||
|
import org.gcube.common.security.secrets.Secret;
|
||||||
|
import org.gcube.smartgears.configuration.PersistenceConfiguration;
|
||||||
import org.gcube.smartgears.configuration.application.ApplicationConfiguration;
|
import org.gcube.smartgears.configuration.application.ApplicationConfiguration;
|
||||||
import org.gcube.smartgears.context.Properties;
|
import org.gcube.smartgears.context.Properties;
|
||||||
import org.gcube.smartgears.context.container.ContainerContext;
|
import org.gcube.smartgears.context.container.ContainerContext;
|
||||||
import org.gcube.smartgears.lifecycle.application.ApplicationLifecycle;
|
import org.gcube.smartgears.lifecycle.application.ApplicationLifecycle;
|
||||||
import org.gcube.smartgears.persistence.Persistence;
|
import org.gcube.smartgears.persistence.PersistenceWriter;
|
||||||
|
import org.gcube.smartgears.security.secrets.GCubeKeyCloakSecretFactory;
|
||||||
|
import org.gcube.smartgears.security.secrets.LegacyGCubeTokenSecretFactory;
|
||||||
|
import org.gcube.smartgears.security.secrets.SecretFactory;
|
||||||
|
import org.gcube.smartgears.utils.Utils;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import jakarta.servlet.ServletContext;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Default {@link ApplicationContext} implementation.
|
* Default {@link ApplicationContext} implementation.
|
||||||
|
@ -20,13 +39,24 @@ import org.gcube.smartgears.persistence.Persistence;
|
||||||
*/
|
*/
|
||||||
public class DefaultApplicationContext implements ApplicationContext {
|
public class DefaultApplicationContext implements ApplicationContext {
|
||||||
|
|
||||||
|
private static Logger log = LoggerFactory.getLogger(DefaultApplicationContext.class);
|
||||||
|
|
||||||
private final ContainerContext container;
|
private final ContainerContext container;
|
||||||
private final ServletContext sctx;
|
private final ServletContext sctx;
|
||||||
private final ApplicationConfiguration configuration;
|
private final ApplicationConfiguration configuration;
|
||||||
private final ApplicationLifecycle lifecycle;
|
private final ApplicationLifecycle lifecycle;
|
||||||
private final Properties properties;
|
private final Properties properties;
|
||||||
private final Hub hub;
|
private final Hub hub;
|
||||||
|
private final PersistenceWriter persistenceWriter;
|
||||||
private final String id;
|
private final String id;
|
||||||
|
private Path appSpecificConfigurationFolder;
|
||||||
|
|
||||||
|
private final static String APPS_CONFIG__DIR = "config/apps";
|
||||||
|
|
||||||
|
private static final List<SecretFactory<? extends Secret>> defaultSecretFactories =
|
||||||
|
new LinkedList<SecretFactory<? extends Secret>>(Arrays.asList(new GCubeKeyCloakSecretFactory(), new LegacyGCubeTokenSecretFactory()));
|
||||||
|
|
||||||
|
private List<SecretFactory<? extends Secret>> allowedSecretFactories = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Crates an intance with mandatory parameters
|
* Crates an intance with mandatory parameters
|
||||||
|
@ -37,14 +67,59 @@ public class DefaultApplicationContext implements ApplicationContext {
|
||||||
* @param lifecycle the lifecycle
|
* @param lifecycle the lifecycle
|
||||||
* @param properties the properties
|
* @param properties the properties
|
||||||
*/
|
*/
|
||||||
public DefaultApplicationContext(String id,ContainerContext container,ServletContext sctx,ApplicationConfiguration configuration, Hub hub, ApplicationLifecycle lifecycle, Properties properties) {
|
public DefaultApplicationContext(ContainerContext container,ServletContext sctx,ApplicationConfiguration configuration, Hub hub, ApplicationLifecycle lifecycle, Properties properties) {
|
||||||
|
|
||||||
|
PersistenceConfiguration persistenceWriterConf = configuration.persistenceConfiguration();
|
||||||
|
|
||||||
|
try {
|
||||||
|
persistenceWriter = persistenceWriterConf.getImplementationClass().getDeclaredConstructor().newInstance();
|
||||||
|
persistenceWriter.configure(persistenceWriterConf.getWriterConfiguration());
|
||||||
|
}catch (Exception e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
File file = persistenceWriter.file(profile_file_path);
|
||||||
|
String id = null;
|
||||||
|
if (file.exists()) {
|
||||||
|
log.info("loading persisted state for application {}", sctx.getContextPath());
|
||||||
|
try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file))) {
|
||||||
|
id = (String) ois.readObject();
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("error loading persisted state, creating new uuid", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (id == null)
|
||||||
|
id = UUID.randomUUID().toString();
|
||||||
|
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.container=container;
|
this.container=container;
|
||||||
this.sctx = sctx;
|
this.sctx = sctx;
|
||||||
this.configuration=configuration;
|
this.configuration=configuration;
|
||||||
this.hub=hub;
|
this.hub=hub;
|
||||||
this.lifecycle = lifecycle;
|
this.lifecycle = lifecycle;
|
||||||
|
this.appSpecificConfigurationFolder = getApplicationSpecificConfig();
|
||||||
this.properties=properties;
|
this.properties=properties;
|
||||||
|
|
||||||
|
if (this.configuration.allowedSecrets()!=null && this.configuration.allowedSecrets().size()>0) {
|
||||||
|
this.allowedSecretFactories = new LinkedList<SecretFactory<? extends Secret>>();
|
||||||
|
for (String clazz : this.configuration.allowedSecrets() )
|
||||||
|
try {
|
||||||
|
Object obj = Class.forName(clazz).getConstructor().newInstance();
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
SecretFactory<? extends Secret> factory = SecretFactory.class.cast(obj);
|
||||||
|
this.allowedSecretFactories.add(factory);
|
||||||
|
} catch (InstantiationException | IllegalAccessException | IllegalArgumentException
|
||||||
|
| InvocationTargetException | NoSuchMethodException | SecurityException
|
||||||
|
| ClassNotFoundException e) {
|
||||||
|
log.warn("declared secret factory {} instantiation error",clazz, e);
|
||||||
|
} catch (ClassCastException cc) {
|
||||||
|
log.warn("declared secret factory {} is not implementation of SecretFacory class",clazz, cc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.allowedSecretFactories == null || this.allowedSecretFactories.size()==0 )
|
||||||
|
this.allowedSecretFactories = defaultSecretFactories;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -52,7 +127,20 @@ public class DefaultApplicationContext implements ApplicationContext {
|
||||||
* @param context the other instance
|
* @param context the other instance
|
||||||
*/
|
*/
|
||||||
public DefaultApplicationContext(ApplicationContext context) {
|
public DefaultApplicationContext(ApplicationContext context) {
|
||||||
this(context.id(), context.container(),context.application(),context.configuration(),context.events(), context.lifecycle(), new Properties(context.properties()));
|
this(context.id(), context.persistence(), context.container(),context.application(),context.configuration(),context.events(), context.lifecycle(), new Properties(context.properties()), context.allowedSecretFactories());
|
||||||
|
}
|
||||||
|
|
||||||
|
private DefaultApplicationContext(String id, PersistenceWriter writer, ContainerContext container,ServletContext sctx,ApplicationConfiguration configuration, Hub hub, ApplicationLifecycle lifecycle, Properties properties, List<SecretFactory<? extends Secret>> allowedSecretFactories) {
|
||||||
|
this.id = id;
|
||||||
|
this.container=container;
|
||||||
|
this.sctx = sctx;
|
||||||
|
this.configuration=configuration;
|
||||||
|
this.hub=hub;
|
||||||
|
this.lifecycle = lifecycle;
|
||||||
|
this.properties=properties;
|
||||||
|
this.persistenceWriter = writer;
|
||||||
|
this.allowedSecretFactories = allowedSecretFactories;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -65,16 +153,6 @@ public class DefaultApplicationContext implements ApplicationContext {
|
||||||
return container;
|
return container;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
@SuppressWarnings("all")
|
|
||||||
public <T> T profile(Class<T> type) {
|
|
||||||
|
|
||||||
if (type==GCoreEndpoint.class)
|
|
||||||
return (T) properties().lookup(profile_property).value(GCoreEndpoint.class);
|
|
||||||
|
|
||||||
throw new IllegalArgumentException("unsupported profile type: "+type);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String name() { //little shortcut for ease of logging
|
public String name() { //little shortcut for ease of logging
|
||||||
return configuration.name();
|
return configuration.name();
|
||||||
|
@ -96,8 +174,8 @@ public class DefaultApplicationContext implements ApplicationContext {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Persistence persistence() {
|
public PersistenceWriter persistence() {
|
||||||
return configuration.persistence();
|
return persistenceWriter;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -110,4 +188,45 @@ public class DefaultApplicationContext implements ApplicationContext {
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the authorization provider.
|
||||||
|
* @return the AuhtorizationProvider
|
||||||
|
**/
|
||||||
|
public AuthorizationProvider authorizationProvider() {
|
||||||
|
return container().authorizationProvider();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Path appSpecificConfigurationFolder() {
|
||||||
|
return this.appSpecificConfigurationFolder;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Path getApplicationSpecificConfig(){
|
||||||
|
String home = Utils.home();
|
||||||
|
|
||||||
|
|
||||||
|
File homeDir = new File(home);
|
||||||
|
|
||||||
|
if (!(homeDir.exists() && homeDir.isDirectory() && homeDir.canRead()))
|
||||||
|
throw new IllegalStateException("invalid node configuration: home " + home
|
||||||
|
+ " does not exist or is not a directory or cannot be accessed in read mode");
|
||||||
|
|
||||||
|
Path appSpecificConfigurationPath = Paths.get(home, APPS_CONFIG__DIR, this.sctx.getContextPath());
|
||||||
|
|
||||||
|
File appSpecificConfiguration = appSpecificConfigurationPath.toFile();
|
||||||
|
|
||||||
|
if (!(appSpecificConfiguration.exists() && appSpecificConfiguration.isDirectory() && appSpecificConfiguration.canRead())) {
|
||||||
|
log.warn("specific configuration folder for {} not found", this.sctx.getContextPath());
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
log.info("reading specific app configuration folder @ {} ", appSpecificConfiguration.getAbsolutePath());
|
||||||
|
|
||||||
|
return appSpecificConfigurationPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<SecretFactory<? extends Secret>> allowedSecretFactories() {
|
||||||
|
return this.allowedSecretFactories;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
package org.gcube.smartgears.context.container;
|
package org.gcube.smartgears.context.container;
|
||||||
|
|
||||||
import org.gcube.common.events.Hub;
|
import org.gcube.common.events.Hub;
|
||||||
|
import org.gcube.common.security.factories.AuthorizationProvider;
|
||||||
import org.gcube.smartgears.configuration.container.ContainerConfiguration;
|
import org.gcube.smartgears.configuration.container.ContainerConfiguration;
|
||||||
import org.gcube.smartgears.context.Properties;
|
import org.gcube.smartgears.context.Properties;
|
||||||
import org.gcube.smartgears.lifecycle.container.ContainerLifecycle;
|
import org.gcube.smartgears.lifecycle.container.ContainerLifecycle;
|
||||||
import org.gcube.smartgears.persistence.Persistence;
|
import org.gcube.smartgears.persistence.PersistenceWriter;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The management context of the container.
|
* The management context of the container.
|
||||||
|
@ -21,11 +22,6 @@ public interface ContainerContext {
|
||||||
*/
|
*/
|
||||||
ContainerConfiguration configuration();
|
ContainerConfiguration configuration();
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the resource profile of a given type of the container.
|
|
||||||
* @return the profile
|
|
||||||
*/
|
|
||||||
<T> T profile(Class<T> type);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the lifecycle of the container
|
* Returns the lifecycle of the container
|
||||||
|
@ -43,7 +39,7 @@ public interface ContainerContext {
|
||||||
* Returns the persistence manager of the container.
|
* Returns the persistence manager of the container.
|
||||||
* @return the manager
|
* @return the manager
|
||||||
*/
|
*/
|
||||||
Persistence persistence();
|
PersistenceWriter persistenceWriter();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the properties of the container.
|
* Returns the properties of the container.
|
||||||
|
@ -53,4 +49,8 @@ public interface ContainerContext {
|
||||||
|
|
||||||
String id();
|
String id();
|
||||||
|
|
||||||
|
|
||||||
|
AuthorizationProvider authorizationProvider();
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,21 @@
|
||||||
package org.gcube.smartgears.context.container;
|
package org.gcube.smartgears.context.container;
|
||||||
|
|
||||||
import static org.gcube.smartgears.Constants.*;
|
import static org.gcube.smartgears.Constants.container_profile_file_path;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.ObjectInputStream;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
import org.gcube.common.events.Hub;
|
import org.gcube.common.events.Hub;
|
||||||
import org.gcube.common.resources.gcore.HostingNode;
|
import org.gcube.common.security.factories.AuthorizationProvider;
|
||||||
|
import org.gcube.smartgears.configuration.PersistenceConfiguration;
|
||||||
import org.gcube.smartgears.configuration.container.ContainerConfiguration;
|
import org.gcube.smartgears.configuration.container.ContainerConfiguration;
|
||||||
import org.gcube.smartgears.context.Properties;
|
import org.gcube.smartgears.context.Properties;
|
||||||
import org.gcube.smartgears.lifecycle.container.ContainerLifecycle;
|
import org.gcube.smartgears.lifecycle.container.ContainerLifecycle;
|
||||||
import org.gcube.smartgears.persistence.Persistence;
|
import org.gcube.smartgears.persistence.PersistenceWriter;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Default {@link ContainerContext} implementation.
|
* Default {@link ContainerContext} implementation.
|
||||||
|
@ -16,11 +25,15 @@ import org.gcube.smartgears.persistence.Persistence;
|
||||||
*/
|
*/
|
||||||
public class DefaultContainerContext implements ContainerContext {
|
public class DefaultContainerContext implements ContainerContext {
|
||||||
|
|
||||||
|
private static Logger log = LoggerFactory.getLogger(DefaultContainerContext.class);
|
||||||
|
|
||||||
private final ContainerConfiguration configuration;
|
private final ContainerConfiguration configuration;
|
||||||
private final ContainerLifecycle lifecycle;
|
private final ContainerLifecycle lifecycle;
|
||||||
private final Properties properties;
|
private final Properties properties;
|
||||||
private final Hub hub;
|
private final Hub hub;
|
||||||
|
private final AuthorizationProvider authorizationProvider;
|
||||||
private final String id;
|
private final String id;
|
||||||
|
private final PersistenceWriter persistenceWriter;
|
||||||
/**
|
/**
|
||||||
* Creates an instance with mandatory parameters.
|
* Creates an instance with mandatory parameters.
|
||||||
* @param configuration the configuration
|
* @param configuration the configuration
|
||||||
|
@ -28,23 +41,49 @@ public class DefaultContainerContext implements ContainerContext {
|
||||||
* @param lifecycle the lifecycle
|
* @param lifecycle the lifecycle
|
||||||
* @param properties the properties
|
* @param properties the properties
|
||||||
*/
|
*/
|
||||||
public DefaultContainerContext(String id,ContainerConfiguration configuration, Hub hub, ContainerLifecycle lifecycle,
|
public DefaultContainerContext(ContainerConfiguration configuration, Hub hub, ContainerLifecycle lifecycle, AuthorizationProvider authProvider,
|
||||||
Properties properties) {
|
Properties properties) {
|
||||||
this.id = id;
|
|
||||||
this.configuration=configuration;
|
this.configuration=configuration;
|
||||||
this.hub=hub;
|
this.hub=hub;
|
||||||
this.lifecycle = lifecycle;
|
this.lifecycle = lifecycle;
|
||||||
this.properties=properties;
|
this.properties=properties;
|
||||||
|
this.authorizationProvider = authProvider;
|
||||||
|
|
||||||
|
PersistenceConfiguration persistenceWriterConf = configuration.persistenceConfiguration();
|
||||||
|
|
||||||
|
try {
|
||||||
|
persistenceWriter = persistenceWriterConf.getImplementationClass().getDeclaredConstructor().newInstance();
|
||||||
|
persistenceWriter.configure(persistenceWriterConf.getWriterConfiguration());
|
||||||
|
}catch (Exception e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("all")
|
File file = persistenceWriter.file(container_profile_file_path);
|
||||||
public <T> T profile(Class<T> type) {
|
|
||||||
|
|
||||||
if (type==HostingNode.class)
|
String id = null;
|
||||||
return (T) properties().lookup(container_profile_property).value(HostingNode.class);
|
if (file.exists()) {
|
||||||
|
log.info("loading persisted state for container");
|
||||||
|
try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file))) {
|
||||||
|
id = (String) ois.readObject();
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("error loading persisted state, creating new uuid", e);
|
||||||
|
}
|
||||||
|
|
||||||
throw new IllegalArgumentException("unsupported profile type: "+type);
|
}
|
||||||
};
|
if (id == null) {
|
||||||
|
id = UUID.randomUUID().toString();
|
||||||
|
log.info("container id created is {}", id);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
this.id = id;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
public HostingNode profile() {
|
||||||
|
return properties().lookup(container_profile_property).value(HostingNode.class);
|
||||||
|
};*/
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ContainerConfiguration configuration() {
|
public ContainerConfiguration configuration() {
|
||||||
|
@ -62,8 +101,8 @@ public class DefaultContainerContext implements ContainerContext {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Persistence persistence() {
|
public PersistenceWriter persistenceWriter() {
|
||||||
return configuration.persistence();
|
return persistenceWriter;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -76,6 +115,8 @@ public class DefaultContainerContext implements ContainerContext {
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public AuthorizationProvider authorizationProvider() {
|
||||||
|
return authorizationProvider;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,12 +4,12 @@ import java.io.IOException;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import javax.servlet.ServletException;
|
import jakarta.servlet.ServletException;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
import org.gcube.smartgears.Constants;
|
import org.gcube.smartgears.Constants;
|
||||||
import org.gcube.smartgears.configuration.application.Exclude;
|
import org.gcube.smartgears.configuration.application.GCubeExclude;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A resource-specifc API handled by an {@link HttpController}.
|
* A resource-specifc API handled by an {@link HttpController}.
|
||||||
|
@ -53,8 +53,8 @@ public abstract class ApiResource extends HttpExtension {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Set<Exclude> excludes() {
|
public Set<GCubeExclude> excludes() {
|
||||||
return Collections.singleton(new Exclude(Constants.root_mapping+mapping()));
|
return Collections.singleton(new GCubeExclude(Constants.root_mapping+mapping()));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -2,9 +2,9 @@ package org.gcube.smartgears.extensions;
|
||||||
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import javax.servlet.Servlet;
|
import jakarta.servlet.Servlet;
|
||||||
|
|
||||||
import org.gcube.smartgears.configuration.application.Exclude;
|
import org.gcube.smartgears.configuration.application.GCubeExclude;
|
||||||
import org.gcube.smartgears.context.application.ApplicationContext;
|
import org.gcube.smartgears.context.application.ApplicationContext;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -22,6 +22,8 @@ public interface ApplicationExtension extends Servlet {
|
||||||
*/
|
*/
|
||||||
void init(ApplicationContext context) throws Exception;
|
void init(ApplicationContext context) throws Exception;
|
||||||
|
|
||||||
|
void stop();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the name of this extension.
|
* Returns the name of this extension.
|
||||||
* @return the name
|
* @return the name
|
||||||
|
@ -39,5 +41,5 @@ public interface ApplicationExtension extends Servlet {
|
||||||
* Returns the set of request paths that should be excluded from request management.
|
* Returns the set of request paths that should be excluded from request management.
|
||||||
* @return the set of request paths that should be excluded from request management
|
* @return the set of request paths that should be excluded from request management
|
||||||
*/
|
*/
|
||||||
Set<Exclude> excludes();
|
Set<GCubeExclude> excludes();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,13 @@
|
||||||
package org.gcube.smartgears.extensions;
|
package org.gcube.smartgears.extensions;
|
||||||
|
|
||||||
import static org.gcube.smartgears.Constants.*;
|
import static org.gcube.smartgears.Constants.accept;
|
||||||
import static org.gcube.smartgears.handlers.application.request.RequestError.*;
|
import static org.gcube.smartgears.Constants.allow;
|
||||||
import static org.gcube.smartgears.utils.Utils.*;
|
import static org.gcube.smartgears.Constants.content_type;
|
||||||
|
import static org.gcube.smartgears.handlers.application.request.RequestError.incoming_contenttype_unsupported_error;
|
||||||
|
import static org.gcube.smartgears.handlers.application.request.RequestError.method_unsupported_error;
|
||||||
|
import static org.gcube.smartgears.handlers.application.request.RequestError.outgoing_contenttype_unsupported_error;
|
||||||
|
import static org.gcube.smartgears.handlers.application.request.RequestError.resource_notfound_error;
|
||||||
|
import static org.gcube.smartgears.utils.Utils.notNull;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
@ -11,13 +16,13 @@ import java.util.LinkedHashSet;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import javax.servlet.ServletException;
|
import jakarta.servlet.ServletException;
|
||||||
import javax.servlet.ServletRequest;
|
import jakarta.servlet.ServletRequest;
|
||||||
import javax.servlet.ServletResponse;
|
import jakarta.servlet.ServletResponse;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
import org.gcube.smartgears.configuration.application.Exclude;
|
import org.gcube.smartgears.configuration.application.GCubeExclude;
|
||||||
import org.gcube.smartgears.context.application.ApplicationContext;
|
import org.gcube.smartgears.context.application.ApplicationContext;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -69,9 +74,17 @@ public class HttpController extends HttpExtension {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Set<Exclude> excludes() {
|
public void stop(){
|
||||||
|
for (ApiResource resource : resources.values())
|
||||||
|
resource.stop();
|
||||||
|
|
||||||
Set<Exclude> resourceExcludes = new LinkedHashSet<Exclude>();
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<GCubeExclude> excludes() {
|
||||||
|
|
||||||
|
Set<GCubeExclude> resourceExcludes = new LinkedHashSet<GCubeExclude>();
|
||||||
|
|
||||||
for (ApiResource resource : resources.values())
|
for (ApiResource resource : resources.values())
|
||||||
resourceExcludes.addAll(resource.excludes());
|
resourceExcludes.addAll(resource.excludes());
|
||||||
|
@ -176,8 +189,6 @@ public class HttpController extends HttpExtension {
|
||||||
case OPTIONS:
|
case OPTIONS:
|
||||||
resource.doOptions(request, response);
|
resource.doOptions(request, response);
|
||||||
break;
|
break;
|
||||||
case TRACE:
|
|
||||||
resource.doTrace(request, response);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,17 +1,15 @@
|
||||||
package org.gcube.smartgears.extensions;
|
package org.gcube.smartgears.extensions;
|
||||||
|
|
||||||
import static org.gcube.common.events.impl.Utils.*;
|
import static org.gcube.common.events.impl.Utils.valid;
|
||||||
|
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import javax.servlet.http.HttpServlet;
|
import jakarta.servlet.http.HttpServlet;
|
||||||
import javax.xml.bind.annotation.XmlAttribute;
|
|
||||||
|
|
||||||
import org.gcube.common.validator.annotations.NotEmpty;
|
import org.gcube.common.validator.annotations.NotEmpty;
|
||||||
import org.gcube.smartgears.configuration.application.Exclude;
|
import org.gcube.smartgears.configuration.application.GCubeExclude;
|
||||||
import org.gcube.smartgears.context.application.ApplicationContext;
|
import org.gcube.smartgears.context.application.ApplicationContext;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An {@link ApplicationExtension} that implements the {@link HttpServlet} interface
|
* An {@link ApplicationExtension} that implements the {@link HttpServlet} interface
|
||||||
*
|
*
|
||||||
|
@ -27,13 +25,31 @@ public abstract class HttpExtension extends HttpServlet implements ApplicationEx
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public static enum Method {
|
public static enum Method {
|
||||||
GET, PUT, POST, HEAD, DELETE, OPTIONS, TRACE
|
GET("GET"),
|
||||||
|
PUT("PUT"),
|
||||||
|
POST("POST"),
|
||||||
|
HEAD("HEAD"),
|
||||||
|
DELETE("DELETE"),
|
||||||
|
OPTIONS("OPTIONS");
|
||||||
|
|
||||||
|
|
||||||
|
private String value;
|
||||||
|
|
||||||
|
|
||||||
|
private Method(String value) {
|
||||||
|
this.value = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
@XmlAttribute @NotEmpty
|
|
||||||
|
public String getValue() {
|
||||||
|
return this.value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotEmpty
|
||||||
private String name;
|
private String name;
|
||||||
|
|
||||||
@XmlAttribute @NotEmpty
|
@NotEmpty
|
||||||
private String mapping;
|
private String mapping;
|
||||||
|
|
||||||
private ApplicationContext context;
|
private ApplicationContext context;
|
||||||
|
@ -50,7 +66,7 @@ public abstract class HttpExtension extends HttpServlet implements ApplicationEx
|
||||||
}
|
}
|
||||||
|
|
||||||
//extensions use init(context) instead
|
//extensions use init(context) instead
|
||||||
public final void init() throws javax.servlet.ServletException {
|
public final void init() throws jakarta.servlet.ServletException {
|
||||||
};
|
};
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -59,8 +75,11 @@ public abstract class HttpExtension extends HttpServlet implements ApplicationEx
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Set<Exclude> excludes() {
|
public void stop() {}
|
||||||
return new HashSet<Exclude>(); //all managed by default
|
|
||||||
|
@Override
|
||||||
|
public Set<GCubeExclude> excludes() {
|
||||||
|
return new HashSet<GCubeExclude>(); //all managed by default
|
||||||
}
|
}
|
||||||
|
|
||||||
protected ApplicationContext context() {
|
protected ApplicationContext context() {
|
||||||
|
|
|
@ -2,14 +2,14 @@ package org.gcube.smartgears.extensions;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
import javax.servlet.Filter;
|
import jakarta.servlet.Filter;
|
||||||
import javax.servlet.FilterChain;
|
import jakarta.servlet.FilterChain;
|
||||||
import javax.servlet.FilterConfig;
|
import jakarta.servlet.FilterConfig;
|
||||||
import javax.servlet.ServletException;
|
import jakarta.servlet.ServletException;
|
||||||
import javax.servlet.ServletRequest;
|
import jakarta.servlet.ServletRequest;
|
||||||
import javax.servlet.ServletResponse;
|
import jakarta.servlet.ServletResponse;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
import org.gcube.smartgears.handlers.application.request.RequestException;
|
import org.gcube.smartgears.handlers.application.request.RequestException;
|
||||||
import org.gcube.smartgears.utils.Utils;
|
import org.gcube.smartgears.utils.Utils;
|
||||||
|
@ -23,6 +23,7 @@ import org.gcube.smartgears.utils.Utils;
|
||||||
*/
|
*/
|
||||||
public class RequestExceptionBarrier implements Filter {
|
public class RequestExceptionBarrier implements Filter {
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void init(FilterConfig filterConfig) throws ServletException {
|
public void init(FilterConfig filterConfig) throws ServletException {
|
||||||
}
|
}
|
||||||
|
@ -32,10 +33,8 @@ public class RequestExceptionBarrier implements Filter {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
|
|
||||||
chain.doFilter(request, response);
|
chain.doFilter(request, response);
|
||||||
|
|
||||||
|
|
||||||
} catch (Throwable t) {
|
} catch (Throwable t) {
|
||||||
|
|
||||||
Utils.handleError(HttpServletRequest.class.cast(request), HttpServletResponse.class.cast(response), t);
|
Utils.handleError(HttpServletRequest.class.cast(request), HttpServletResponse.class.cast(response), t);
|
||||||
|
|
|
@ -1,17 +1,16 @@
|
||||||
package org.gcube.smartgears.extensions.resource;
|
package org.gcube.smartgears.extensions.resource;
|
||||||
|
|
||||||
import static org.gcube.smartgears.Constants.application_xml;
|
import static org.gcube.smartgears.Constants.application_json;
|
||||||
import static org.gcube.smartgears.extensions.HttpExtension.Method.GET;
|
import static org.gcube.smartgears.extensions.HttpExtension.Method.GET;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
import javax.servlet.ServletException;
|
import jakarta.servlet.ServletException;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
import org.gcube.common.resources.gcore.Resources;
|
import org.gcube.com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
import org.gcube.smartgears.configuration.application.ApplicationConfiguration;
|
import org.gcube.smartgears.configuration.application.ApplicationConfiguration;
|
||||||
import org.gcube.smartgears.configuration.application.BridgedApplicationConfiguration;
|
|
||||||
import org.gcube.smartgears.extensions.ApiResource;
|
import org.gcube.smartgears.extensions.ApiResource;
|
||||||
import org.gcube.smartgears.extensions.ApiSignature;
|
import org.gcube.smartgears.extensions.ApiSignature;
|
||||||
|
|
||||||
|
@ -27,7 +26,7 @@ public class ConfigurationResource extends ApiResource {
|
||||||
|
|
||||||
public static final String mapping = "/configuration";
|
public static final String mapping = "/configuration";
|
||||||
|
|
||||||
private static final ApiSignature signature = handles(mapping).with(method(GET).produces(application_xml));
|
private static final ApiSignature signature = handles(mapping).with(method(GET).produces(application_json));
|
||||||
|
|
||||||
ConfigurationResource() {
|
ConfigurationResource() {
|
||||||
super(signature);
|
super(signature);
|
||||||
|
@ -37,8 +36,8 @@ public class ConfigurationResource extends ApiResource {
|
||||||
@Override
|
@Override
|
||||||
public void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
|
public void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
|
||||||
|
|
||||||
ApplicationConfiguration config = BridgedApplicationConfiguration.class.cast(context().configuration()).inner();
|
ApplicationConfiguration config = context().configuration();
|
||||||
Resources.marshal(config,resp.getWriter());
|
new ObjectMapper().writeValue(resp.getWriter(), config);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,29 +4,24 @@ import static org.gcube.smartgears.Constants.application_xhtml;
|
||||||
import static org.gcube.smartgears.Constants.frontpage_file_path;
|
import static org.gcube.smartgears.Constants.frontpage_file_path;
|
||||||
import static org.gcube.smartgears.extensions.HttpExtension.Method.GET;
|
import static org.gcube.smartgears.extensions.HttpExtension.Method.GET;
|
||||||
import static org.gcube.smartgears.handlers.application.request.RequestError.application_error;
|
import static org.gcube.smartgears.handlers.application.request.RequestError.application_error;
|
||||||
import static org.gcube.smartgears.provider.ProviderFactory.provider;
|
|
||||||
import static org.gcube.smartgears.utils.Utils.closeSafely;
|
import static org.gcube.smartgears.utils.Utils.closeSafely;
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
import javax.servlet.ServletException;
|
import jakarta.servlet.ServletException;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
import org.gcube.common.resources.gcore.GCoreEndpoint;
|
|
||||||
import org.gcube.common.scope.impl.ScopeBean;
|
|
||||||
import org.gcube.smartgears.extensions.ApiResource;
|
import org.gcube.smartgears.extensions.ApiResource;
|
||||||
import org.gcube.smartgears.extensions.ApiSignature;
|
import org.gcube.smartgears.extensions.ApiSignature;
|
||||||
|
import org.gcube.smartgears.provider.ProviderFactory;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
@ -93,42 +88,12 @@ public class FrontPageResource extends ApiResource {
|
||||||
values.put("version", context().configuration().version());
|
values.put("version", context().configuration().version());
|
||||||
|
|
||||||
String infrastructure = context().container().configuration().infrastructure();
|
String infrastructure = context().container().configuration().infrastructure();
|
||||||
StringBuilder voValue = new StringBuilder();
|
|
||||||
|
|
||||||
Collection<String> scopes = context().profile(GCoreEndpoint.class).scopes().asCollection();
|
|
||||||
Set<String> vos = new HashSet<String>();
|
|
||||||
|
|
||||||
//pre-process
|
|
||||||
for (String scope : scopes) {
|
|
||||||
ScopeBean bean = new ScopeBean(scope);
|
|
||||||
switch (bean.type()) {
|
|
||||||
case INFRASTRUCTURE:
|
|
||||||
infrastructure = bean.name();
|
|
||||||
break;
|
|
||||||
case VO:
|
|
||||||
vos.add(bean.name());
|
|
||||||
break;
|
|
||||||
case VRE:
|
|
||||||
vos.add(bean.enclosingScope().name());
|
|
||||||
infrastructure=bean.enclosingScope().enclosingScope().name();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//build vo value
|
|
||||||
int i = 0;
|
|
||||||
int max = vos.size()-1;
|
|
||||||
for (String vo : vos) {
|
|
||||||
String voPrefix = i == 0 ? "" : (i==max?" and ":", ");
|
|
||||||
voValue.append(voPrefix+"<em>" + vo + "</em>");
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
|
|
||||||
values.put("infra", infrastructure);
|
values.put("infra", infrastructure);
|
||||||
values.put("vos", voValue.toString());
|
|
||||||
|
|
||||||
values.put("status", context().lifecycle().state().toString());
|
values.put("status", context().lifecycle().state().toString());
|
||||||
|
|
||||||
values.put("smartgears-version", provider().smartgearsConfiguration().version());
|
values.put("smartgears-version", ProviderFactory.provider().smartgearsConfiguration().getVersion());
|
||||||
|
|
||||||
return values;
|
return values;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 jakarta.servlet.ServletException;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import jakarta.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();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -8,11 +8,9 @@ import static org.gcube.smartgears.handlers.application.request.RequestError.inv
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
import javax.servlet.ServletException;
|
import jakarta.servlet.ServletException;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
import javax.xml.bind.annotation.XmlRootElement;
|
|
||||||
import javax.xml.bind.annotation.XmlValue;
|
|
||||||
|
|
||||||
import org.gcube.common.resources.gcore.Resources;
|
import org.gcube.common.resources.gcore.Resources;
|
||||||
import org.gcube.smartgears.extensions.ApiResource;
|
import org.gcube.smartgears.extensions.ApiResource;
|
||||||
|
@ -86,10 +84,8 @@ public class LifecycleResource extends ApiResource {
|
||||||
|
|
||||||
// helper classes
|
// helper classes
|
||||||
|
|
||||||
@XmlRootElement(name="state")
|
|
||||||
public static class State {
|
public static class State {
|
||||||
|
|
||||||
@XmlValue
|
|
||||||
public String value;
|
public String value;
|
||||||
|
|
||||||
State() {
|
State() {
|
||||||
|
|
|
@ -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 jakarta.servlet.ServletException;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import jakarta.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());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -5,12 +5,10 @@ import static org.gcube.smartgears.extensions.HttpExtension.Method.GET;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
import javax.servlet.ServletException;
|
import jakarta.servlet.ServletException;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
import org.gcube.common.resources.gcore.GCoreEndpoint;
|
|
||||||
import org.gcube.common.resources.gcore.Resources;
|
|
||||||
import org.gcube.smartgears.extensions.ApiResource;
|
import org.gcube.smartgears.extensions.ApiResource;
|
||||||
import org.gcube.smartgears.extensions.ApiSignature;
|
import org.gcube.smartgears.extensions.ApiSignature;
|
||||||
|
|
||||||
|
@ -36,7 +34,8 @@ public class ProfileResource extends ApiResource {
|
||||||
@Override
|
@Override
|
||||||
public void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
|
public void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
|
||||||
|
|
||||||
Resources.marshal(context().profile(GCoreEndpoint.class),resp.getWriter());
|
//Resources.marshal(context().profile(),resp.getWriter());
|
||||||
|
//TODO: return something to show
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
package org.gcube.smartgears.extensions.resource;
|
package org.gcube.smartgears.extensions.resource;
|
||||||
|
|
||||||
import static org.gcube.smartgears.Constants.*;
|
import static org.gcube.smartgears.Constants.remote_management;
|
||||||
|
|
||||||
import javax.xml.bind.annotation.XmlRootElement;
|
|
||||||
|
|
||||||
import org.gcube.smartgears.Constants;
|
import org.gcube.smartgears.Constants;
|
||||||
import org.gcube.smartgears.extensions.ApiResource;
|
import org.gcube.smartgears.extensions.ApiResource;
|
||||||
|
@ -14,7 +12,6 @@ import org.gcube.smartgears.extensions.HttpController;
|
||||||
* @author Fabio Simeoni
|
* @author Fabio Simeoni
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
@XmlRootElement(name = remote_management)
|
|
||||||
public class RemoteResource extends HttpController {
|
public class RemoteResource extends HttpController {
|
||||||
|
|
||||||
private static final String default_mapping = Constants.root_mapping+"/*";
|
private static final String default_mapping = Constants.root_mapping+"/*";
|
||||||
|
@ -27,7 +24,7 @@ public class RemoteResource extends HttpController {
|
||||||
public RemoteResource() {
|
public RemoteResource() {
|
||||||
super(remote_management, default_mapping);
|
super(remote_management, default_mapping);
|
||||||
addResources(new FrontPageResource(), new ConfigurationResource(), new ProfileResource(),
|
addResources(new FrontPageResource(), new ConfigurationResource(), new ProfileResource(),
|
||||||
new LifecycleResource());
|
new LifecycleResource(), new MetricsResource(), new HealthResource());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -21,6 +21,7 @@ public abstract class AbstractHandler {
|
||||||
return this.getClass().getCanonicalName().equals(handler.getClass().getCanonicalName());
|
return this.getClass().getCanonicalName().equals(handler.getClass().getCanonicalName());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//so far, largely a placeholder for future cross-handler behaviour
|
//so far, largely a placeholder for future cross-handler behaviour
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,20 +4,13 @@ import java.util.Collection;
|
||||||
|
|
||||||
public interface ProfilePublisher {
|
public interface ProfilePublisher {
|
||||||
|
|
||||||
/**
|
void addTo(Collection<String> contexts);
|
||||||
* Adds for the first time the current resource profile of the application in one or more scopes.
|
|
||||||
* @param scopes the scopes
|
|
||||||
*/
|
|
||||||
void addTo(Collection<String> tokens);
|
|
||||||
|
|
||||||
void addToAll();
|
void addToAll();
|
||||||
|
|
||||||
void update();
|
void update();
|
||||||
|
|
||||||
/**
|
void removeFrom(Collection<String> contexts);
|
||||||
* Removes the application from one or more scopes.
|
|
||||||
* @param scopes the scopes
|
|
||||||
*/
|
|
||||||
void removeFrom(Collection<String> tokens);
|
|
||||||
|
|
||||||
}
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
package org.gcube.smartgears.handlers.application;
|
package org.gcube.smartgears.handlers.application;
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
import org.gcube.smartgears.context.application.ApplicationContext;
|
import org.gcube.smartgears.context.application.ApplicationContext;
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,10 @@ public abstract class RequestHandler extends AbstractHandler implements Applicat
|
||||||
|
|
||||||
abstract public String getName();
|
abstract public String getName();
|
||||||
|
|
||||||
|
public boolean isUnfiltrable() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialises the handler.
|
* Initialises the handler.
|
||||||
*
|
*
|
||||||
|
@ -65,4 +69,6 @@ public abstract class RequestHandler extends AbstractHandler implements Applicat
|
||||||
public void stop() {
|
public void stop() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
package org.gcube.smartgears.handlers.application;
|
package org.gcube.smartgears.handlers.application;
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
import org.gcube.smartgears.context.application.ApplicationContext;
|
import org.gcube.smartgears.context.application.ApplicationContext;
|
||||||
|
|
||||||
|
|
|
@ -2,36 +2,31 @@ package org.gcube.smartgears.handlers.application.lifecycle;
|
||||||
|
|
||||||
import static org.gcube.common.events.Observes.Kind.resilient;
|
import static org.gcube.common.events.Observes.Kind.resilient;
|
||||||
import static org.gcube.smartgears.Constants.profile_management;
|
import static org.gcube.smartgears.Constants.profile_management;
|
||||||
import static org.gcube.smartgears.Constants.profile_property;
|
|
||||||
import static org.gcube.smartgears.handlers.ProfileEvents.addToContext;
|
import static org.gcube.smartgears.handlers.ProfileEvents.addToContext;
|
||||||
import static org.gcube.smartgears.handlers.ProfileEvents.changed;
|
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.handlers.ProfileEvents.removeFromContext;
|
||||||
import static org.gcube.smartgears.lifecycle.application.ApplicationLifecycle.activation;
|
import static org.gcube.smartgears.lifecycle.application.ApplicationLifecycle.activation;
|
||||||
import static org.gcube.smartgears.lifecycle.application.ApplicationLifecycle.failure;
|
import static org.gcube.smartgears.lifecycle.application.ApplicationLifecycle.failure;
|
||||||
import static org.gcube.smartgears.lifecycle.application.ApplicationLifecycle.stop;
|
import static org.gcube.smartgears.lifecycle.application.ApplicationLifecycle.stop;
|
||||||
import static org.gcube.smartgears.lifecycle.application.ApplicationState.failed;
|
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
import java.util.concurrent.ScheduledFuture;
|
import java.util.concurrent.ScheduledFuture;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import javax.xml.bind.annotation.XmlRootElement;
|
|
||||||
|
|
||||||
import org.gcube.common.events.Observes;
|
import org.gcube.common.events.Observes;
|
||||||
import org.gcube.common.events.Observes.Kind;
|
import org.gcube.common.events.Observes.Kind;
|
||||||
import org.gcube.common.resources.gcore.GCoreEndpoint;
|
|
||||||
import org.gcube.smartgears.Constants;
|
import org.gcube.smartgears.Constants;
|
||||||
import org.gcube.smartgears.configuration.Mode;
|
import org.gcube.smartgears.configuration.Mode;
|
||||||
import org.gcube.smartgears.context.Property;
|
import org.gcube.smartgears.context.Property;
|
||||||
import org.gcube.smartgears.context.application.ApplicationContext;
|
import org.gcube.smartgears.context.application.ApplicationContext;
|
||||||
import org.gcube.smartgears.handlers.OfflineProfilePublisher;
|
|
||||||
import org.gcube.smartgears.handlers.ProfilePublisher;
|
|
||||||
import org.gcube.smartgears.handlers.application.ApplicationLifecycleEvent;
|
import org.gcube.smartgears.handlers.application.ApplicationLifecycleEvent;
|
||||||
import org.gcube.smartgears.handlers.application.ApplicationLifecycleHandler;
|
import org.gcube.smartgears.handlers.application.ApplicationLifecycleHandler;
|
||||||
import org.gcube.smartgears.lifecycle.application.ApplicationLifecycle;
|
import org.gcube.smartgears.lifecycle.application.ApplicationLifecycle;
|
||||||
import org.gcube.smartgears.lifecycle.application.ApplicationState;
|
import org.gcube.smartgears.lifecycle.application.ApplicationState;
|
||||||
import org.gcube.smartgears.lifecycle.container.ContainerLifecycle;
|
import org.gcube.smartgears.lifecycle.container.ContainerLifecycle;
|
||||||
|
import org.gcube.smartgears.provider.ProviderFactory;
|
||||||
|
import org.gcube.smartgears.publishing.Publisher;
|
||||||
import org.gcube.smartgears.utils.Utils;
|
import org.gcube.smartgears.utils.Utils;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
@ -52,29 +47,24 @@ import org.slf4j.LoggerFactory;
|
||||||
* </ul>
|
* </ul>
|
||||||
*
|
*
|
||||||
* @author Fabio Simeoni
|
* @author Fabio Simeoni
|
||||||
* @see ProfileBuilder
|
|
||||||
* @see ProfilePublisherImpl
|
|
||||||
*/
|
*/
|
||||||
@XmlRootElement(name = profile_management)
|
public class ApplicationProfileManager extends ApplicationLifecycleHandler {
|
||||||
public class ProfileManager extends ApplicationLifecycleHandler {
|
|
||||||
|
|
||||||
Logger log = LoggerFactory.getLogger(ProfileManager.class);
|
Logger log = LoggerFactory.getLogger(ApplicationProfileManager.class);
|
||||||
|
|
||||||
private ApplicationContext context;
|
private ApplicationContext context;
|
||||||
private ProfileBuilder builder;
|
|
||||||
private ProfilePublisher publisher;
|
|
||||||
|
|
||||||
private ScheduledFuture<?> periodicUpdates;
|
private ScheduledFuture<?> periodicUpdates;
|
||||||
|
private static final String PUBLISHED_PROP = "published";
|
||||||
|
private List<Publisher> publishers = ProviderFactory.provider().publishers();
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onStart(ApplicationLifecycleEvent.Start e) {
|
public void onStart(ApplicationLifecycleEvent.Start e) {
|
||||||
|
|
||||||
context = e.context();
|
context = e.context();
|
||||||
builder = new ProfileBuilder(context);
|
|
||||||
|
|
||||||
activated();
|
activated();
|
||||||
|
|
||||||
schedulePeriodicUpdates();
|
|
||||||
// note we don't fire profile events, but wait for the final startup
|
// note we don't fire profile events, but wait for the final startup
|
||||||
// outcome which
|
// outcome which
|
||||||
// will result in a state change. only then we publish and store the
|
// will result in a state change. only then we publish and store the
|
||||||
|
@ -89,16 +79,13 @@ public class ProfileManager extends ApplicationLifecycleHandler {
|
||||||
|
|
||||||
|
|
||||||
private void activated(){
|
private void activated(){
|
||||||
GCoreEndpoint profile = loadOrCreateProfile();
|
|
||||||
|
|
||||||
share(profile);
|
|
||||||
|
|
||||||
publisher = context.container().configuration().mode()!=Mode.offline?
|
|
||||||
new ProfilePublisherImpl(context):
|
|
||||||
new OfflineProfilePublisher();
|
|
||||||
|
|
||||||
|
publishers = context.container().configuration().mode()!=Mode.offline?
|
||||||
|
ProviderFactory.provider().publishers():
|
||||||
|
Collections.emptyList();
|
||||||
|
|
||||||
registerObservers();
|
registerObservers();
|
||||||
|
schedulePeriodicUpdates();
|
||||||
}
|
}
|
||||||
|
|
||||||
// helpers
|
// helpers
|
||||||
|
@ -109,67 +96,69 @@ public class ProfileManager extends ApplicationLifecycleHandler {
|
||||||
@Observes({ activation, stop, failure })
|
@Observes({ activation, stop, failure })
|
||||||
void onChanged(ApplicationLifecycle lc) {
|
void onChanged(ApplicationLifecycle lc) {
|
||||||
|
|
||||||
GCoreEndpoint profile = context.profile(GCoreEndpoint.class);
|
|
||||||
|
|
||||||
profile.profile().deploymentData().status(lc.state().remoteForm());
|
|
||||||
|
|
||||||
log.debug("moving app {} to {}",context.name(), lc.state().remoteForm());
|
log.debug("moving app {} to {}",context.name(), lc.state().remoteForm());
|
||||||
|
|
||||||
// since we do not know the observers, they will deal with
|
// since we do not know the observers, they will deal with
|
||||||
// failures and their consequences
|
// failures and their consequences
|
||||||
// any that comes back will be logged in this event thread
|
// any that comes back will be logged in this event thread
|
||||||
context.events().fire(profile, changed);
|
context.events().fire(context, changed);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
@Observes(value = published)
|
@Observes(value = published)
|
||||||
void shareAfterPublish(GCoreEndpoint profile) {
|
void shareAfterPublish(GCoreEndpoint profile) {
|
||||||
|
|
||||||
share(profile); // publish may produce a new profile instance
|
share(profile); // publish may produce a new profile instance
|
||||||
|
|
||||||
}
|
}*/
|
||||||
|
|
||||||
@Observes(value = changed, kind = Kind.safe)
|
@Observes(value = changed, kind = Kind.safe)
|
||||||
void publishAfterChange(GCoreEndpoint profile) {
|
void publishAfterChange(ApplicationContext context) {
|
||||||
|
|
||||||
boolean firstPublication = profile.scopes().isEmpty();
|
|
||||||
|
|
||||||
//if we've failed before first publication do not try to publish
|
//if we've failed before first publication do not try to publish
|
||||||
//(we may well have failed there)
|
//(we may well have failed there)
|
||||||
|
if (!context.properties().contains(PUBLISHED_PROP)) {
|
||||||
|
log.info("publishing application for the first time");
|
||||||
|
context.properties().add(new Property(PUBLISHED_PROP, true));
|
||||||
|
if (context.lifecycle().state() != ApplicationState.failed) {
|
||||||
|
publishers.forEach(p -> {
|
||||||
try {
|
try {
|
||||||
|
p.create(context,
|
||||||
if (firstPublication) {
|
context.container().authorizationProvider().getContexts());
|
||||||
if (context.lifecycle().state()!= failed)
|
}catch (Exception e) {
|
||||||
publishFirstTime(profile);
|
log.error("cannot publish {} for first time with publisher type {} (see details)",context.name(), p.getClass().getCanonicalName(), e);
|
||||||
}
|
}
|
||||||
else{
|
});
|
||||||
log.debug("update app {} profile",context.name());
|
|
||||||
publisher.update(); // if successful, triggers share.
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception e) {
|
else
|
||||||
|
publishers.forEach(p -> {
|
||||||
log.error("cannot publish "+context.name()+" (see details)", e);
|
try {
|
||||||
|
p.update(context);
|
||||||
// since we've failed no published event is fired and profile
|
}catch (Exception e) {
|
||||||
// will not be stored.
|
log.error("cannot publish {} with publisher type {} (see details)",context.name(), p.getClass().getCanonicalName(), e);
|
||||||
// we do it manually to ensure we leave some local trace of the
|
|
||||||
// changed profile.
|
|
||||||
//TODO: CHECK --- store(profile);
|
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
//registering ContextObserver in container HUB
|
||||||
|
context.container().events().subscribe(new Object() {
|
||||||
|
|
||||||
@Observes(value = addToContext)
|
@Observes(value = addToContext)
|
||||||
void addTo(String token) {
|
void addTo(String scope) {
|
||||||
|
log.info("add_to_context event arrived in app {}", context.name());
|
||||||
|
for (Publisher publisher: publishers)
|
||||||
try {
|
try {
|
||||||
log.trace("publishing application with new token");
|
log.debug("publishing application in context {}", scope);
|
||||||
publisher.addTo(Collections.singleton(token));
|
publisher.create(context,
|
||||||
publisher.update();
|
Collections.singleton(scope));
|
||||||
|
|
||||||
}catch (Exception e) {
|
}catch (Exception e) {
|
||||||
|
|
||||||
log.error("cannot add token {} (see details)",token, e);
|
log.error("cannot add context {} with publisher type {} (see details)",scope, publisher.getClass().getCanonicalName(), e);
|
||||||
|
|
||||||
// since we've failed no published event is fired and profile
|
// since we've failed no published event is fired and profile
|
||||||
// will not be stored.
|
// will not be stored.
|
||||||
|
@ -181,14 +170,16 @@ public class ProfileManager extends ApplicationLifecycleHandler {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Observes(value = removeFromContext)
|
@Observes(value = removeFromContext)
|
||||||
void removeFrom(String token) {
|
void removeFrom(String scope) {
|
||||||
|
log.info("remove_from_context event arrived in app {}", context.name());
|
||||||
|
for (Publisher publisher: publishers)
|
||||||
try {
|
try {
|
||||||
log.trace("unpublishing application with token");
|
log.debug("unpublishing application from scope {}", scope);
|
||||||
publisher.removeFrom(Collections.singleton(token));
|
publisher.remove(context,
|
||||||
publisher.update();
|
Collections.singleton(scope));
|
||||||
}catch (Exception e) {
|
}catch (Exception e) {
|
||||||
|
|
||||||
log.error("cannot remove token {} (see details)",token, e);
|
log.error("cannot remove scope {} with publisher type {} (see details)",scope, publisher.getClass().getCanonicalName(), e);
|
||||||
|
|
||||||
// since we've failed no published event is fired and profile
|
// since we've failed no published event is fired and profile
|
||||||
// will not be stored.
|
// will not be stored.
|
||||||
|
@ -199,51 +190,6 @@ public class ProfileManager extends ApplicationLifecycleHandler {
|
||||||
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private void share(GCoreEndpoint profile) {
|
|
||||||
|
|
||||||
log.trace("sharing profile for {}", context.name());
|
|
||||||
|
|
||||||
context.properties().add(new Property(profile_property, profile));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void publishFirstTime(GCoreEndpoint profile) {
|
|
||||||
|
|
||||||
try {
|
|
||||||
|
|
||||||
publisher.addToAll();
|
|
||||||
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.warn("publishing failed",e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private GCoreEndpoint loadOrCreateProfile() {
|
|
||||||
|
|
||||||
return create();
|
|
||||||
}
|
|
||||||
|
|
||||||
private GCoreEndpoint create() {
|
|
||||||
|
|
||||||
log.info("creating profile for {}", context.name());
|
|
||||||
|
|
||||||
try {
|
|
||||||
|
|
||||||
GCoreEndpoint profile = new GCoreEndpoint();
|
|
||||||
profile.setId(context.id());
|
|
||||||
|
|
||||||
builder.fill(profile);
|
|
||||||
|
|
||||||
return profile;
|
|
||||||
|
|
||||||
} catch (RuntimeException e) {
|
|
||||||
|
|
||||||
// this is a critical startup failure: it will fail the application
|
|
||||||
throw new RuntimeException("cannot create profile for " + context.name(), e);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -270,16 +216,16 @@ public class ProfileManager extends ApplicationLifecycleHandler {
|
||||||
|
|
||||||
final Runnable updateTask = new Runnable() {
|
final Runnable updateTask = new Runnable() {
|
||||||
public void run() {
|
public void run() {
|
||||||
GCoreEndpoint profile = context.profile(GCoreEndpoint.class);
|
|
||||||
|
|
||||||
//if handling of event generates failures these will be reported
|
//if handling of event generates failures these will be reported
|
||||||
//for resilience we do not fail the application
|
//for resilience we do not fail the application
|
||||||
log.trace("firing change event on application {} profile", context.name());
|
log.trace("firing change event on application {} ", context.name());
|
||||||
context.events().fire(profile,changed);
|
context.events().fire(context,changed);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
periodicUpdates = Utils.scheduledServicePool.scheduleAtFixedRate(updateTask, Constants.application_republish_frequency_in_minutes, Constants.application_republish_frequency_in_minutes , TimeUnit.MINUTES);
|
periodicUpdates = Utils.scheduledServicePool.scheduleAtFixedRate(updateTask,
|
||||||
|
Constants.application_republish_frequency_in_minutes,
|
||||||
|
Constants.application_republish_frequency_in_minutes , TimeUnit.MINUTES);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -294,7 +240,7 @@ public class ProfileManager extends ApplicationLifecycleHandler {
|
||||||
periodicUpdates=null;
|
periodicUpdates=null;
|
||||||
}
|
}
|
||||||
catch(Exception e) {
|
catch(Exception e) {
|
||||||
log.warn("could not stop periodic updates of application {} profile", context.name(),e);
|
log.warn("could not stop periodic updates of application {}", context.name(),e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -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,16 +1,10 @@
|
||||||
package org.gcube.smartgears.handlers.application.request;
|
package org.gcube.smartgears.handlers.application.request;
|
||||||
|
|
||||||
import static org.gcube.smartgears.Constants.called_method_header;
|
|
||||||
|
|
||||||
import javax.xml.bind.annotation.XmlRootElement;
|
|
||||||
|
|
||||||
import org.gcube.accounting.datamodel.UsageRecord.OperationResult;
|
import org.gcube.accounting.datamodel.UsageRecord.OperationResult;
|
||||||
import org.gcube.accounting.datamodel.usagerecords.ServiceUsageRecord;
|
import org.gcube.accounting.datamodel.usagerecords.ServiceUsageRecord;
|
||||||
import org.gcube.accounting.persistence.AccountingPersistence;
|
import org.gcube.accounting.persistence.AccountingPersistence;
|
||||||
import org.gcube.accounting.persistence.AccountingPersistenceFactory;
|
import org.gcube.accounting.persistence.AccountingPersistenceFactory;
|
||||||
import org.gcube.common.authorization.library.provider.AuthorizationProvider;
|
import org.gcube.common.security.providers.SecretManagerProvider;
|
||||||
import org.gcube.common.authorization.library.provider.SecurityTokenProvider;
|
|
||||||
import org.gcube.common.scope.api.ScopeProvider;
|
|
||||||
import org.gcube.smartgears.Constants;
|
import org.gcube.smartgears.Constants;
|
||||||
import org.gcube.smartgears.configuration.Mode;
|
import org.gcube.smartgears.configuration.Mode;
|
||||||
import org.gcube.smartgears.context.application.ApplicationContext;
|
import org.gcube.smartgears.context.application.ApplicationContext;
|
||||||
|
@ -21,13 +15,13 @@ import org.gcube.smartgears.utils.InnerMethodName;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
@XmlRootElement(name = Constants.request_accounting)
|
|
||||||
public class RequestAccounting extends RequestHandler {
|
public class RequestAccounting extends RequestHandler {
|
||||||
|
|
||||||
private static Logger log = LoggerFactory.getLogger(RequestAccounting.class);
|
private static Logger log = LoggerFactory.getLogger(RequestAccounting.class);
|
||||||
|
|
||||||
private static ThreadLocal<Long> startCallThreadLocal = new ThreadLocal<Long>();
|
private static ThreadLocal<Long> startCallThreadLocal = new ThreadLocal<Long>();
|
||||||
|
|
||||||
|
private static final String UNKNOWN = "Unknown";
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getName() {
|
public String getName() {
|
||||||
|
@ -36,37 +30,41 @@ public class RequestAccounting extends RequestHandler {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handleRequest(RequestEvent e) {
|
public void handleRequest(RequestEvent e) {
|
||||||
ApplicationContext context = e.context();
|
ApplicationContext appContext = e.context();
|
||||||
|
|
||||||
String calledMethod = e.request().getHeader(called_method_header);
|
String context = getContext(appContext);
|
||||||
if (calledMethod==null){
|
|
||||||
calledMethod = e.request().getRequestURI().substring(e.request().getContextPath().length());
|
if (InnerMethodName.get() == null) {
|
||||||
|
String calledMethod = e.request().getRequestURI().substring(e.request().getContextPath().length());
|
||||||
if (calledMethod.isEmpty())
|
if (calledMethod.isEmpty())
|
||||||
calledMethod = "/";
|
calledMethod = "/";
|
||||||
calledMethod = e.request().getMethod() + " " + calledMethod;
|
calledMethod = e.request().getMethod() + " " + calledMethod;
|
||||||
|
InnerMethodName.set(calledMethod);
|
||||||
}
|
}
|
||||||
InnerMethodName.instance.set(calledMethod);
|
|
||||||
String caller = AuthorizationProvider.instance.get()!=null? AuthorizationProvider.instance.get().getClient().getId(): "UNKNOWN";
|
String caller = SecretManagerProvider.get() != null
|
||||||
|
? SecretManagerProvider.get().getOwner().getId()
|
||||||
|
: UNKNOWN;
|
||||||
startCallThreadLocal.set(System.currentTimeMillis());
|
startCallThreadLocal.set(System.currentTimeMillis());
|
||||||
log.info("REQUEST START ON {}:{}({}) CALLED FROM {}@{} IN SCOPE {} ",
|
|
||||||
context.configuration().name(),context.configuration().serviceClass(), InnerMethodName.instance.get(),
|
log.info("REQUEST START ON {}:{}({}) CALLED FROM {}@{} IN SCOPE {} ", appContext.configuration().name(),
|
||||||
caller, e.request().getRemoteHost(), ScopeProvider.instance.get());
|
appContext.configuration().group(), InnerMethodName.get(), caller,
|
||||||
|
e.request().getRemoteHost(), context);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handleResponse(ResponseEvent e) {
|
public void handleResponse(ResponseEvent e) {
|
||||||
ApplicationContext context = e.context();
|
ApplicationContext appContext = e.context();
|
||||||
|
|
||||||
boolean resetScope = false;
|
try {
|
||||||
if (ScopeProvider.instance.get()==null && SecurityTokenProvider.instance.get()==null){
|
|
||||||
String infrastructure = e.context().container().configuration().infrastructure();
|
|
||||||
ScopeProvider.instance.set("/"+infrastructure);
|
|
||||||
resetScope = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
String caller = AuthorizationProvider.instance.get()!=null? AuthorizationProvider.instance.get().getClient().getId(): "UNKNOWN";
|
String context = getContext(appContext);
|
||||||
String callerQualifier = AuthorizationProvider.instance.get()!=null? AuthorizationProvider.instance.get().getTokenQualifier(): "UNKNOWN";
|
|
||||||
|
String caller = SecretManagerProvider.get() != null
|
||||||
|
? SecretManagerProvider.get().getOwner().getId()
|
||||||
|
: UNKNOWN;
|
||||||
|
String callerQualifier = UNKNOWN;
|
||||||
// retieves caller Ip when there is a proxy
|
// retieves caller Ip when there is a proxy
|
||||||
String callerIp = e.request().getHeader("x-forwarded-for");
|
String callerIp = e.request().getHeader("x-forwarded-for");
|
||||||
if (callerIp == null)
|
if (callerIp == null)
|
||||||
|
@ -74,32 +72,55 @@ public class RequestAccounting extends RequestHandler {
|
||||||
|
|
||||||
boolean success = e.response().getStatus() < 400;
|
boolean success = e.response().getStatus() < 400;
|
||||||
|
|
||||||
if (context.container().configuration().mode()!=Mode.offline)
|
if (appContext.container().configuration().mode() != Mode.offline)
|
||||||
generateAccounting(caller,callerQualifier,callerIp==null?"UNKNOWN":callerIp , success, context);
|
generateAccounting(caller, callerQualifier, callerIp == null ? UNKNOWN : callerIp, success, context,
|
||||||
|
appContext);
|
||||||
|
|
||||||
|
long durationInMillis = System.currentTimeMillis() - startCallThreadLocal.get();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Metrics.globalRegistry.timer("smartgears.requests",
|
||||||
|
* "response",Integer.toString(e.response().getStatus()) , "context", context,
|
||||||
|
* "result", success?"SUCCEDED":"FAILED", "caller-ip", callerIp,
|
||||||
|
* "caller-username", caller, "service-class",
|
||||||
|
* appContext.configuration().serviceClass(), "service-name",
|
||||||
|
* appContext.configuration().name(), "method",
|
||||||
|
* InnerMethodName.instance.get()).record(durationInMillis,
|
||||||
|
* TimeUnit.MILLISECONDS);
|
||||||
|
*/
|
||||||
|
|
||||||
log.info("REQUEST SERVED ON {}:{}({}) CALLED FROM {}@{} IN SCOPE {} {}(CODE {}) IN {} millis",
|
log.info("REQUEST SERVED ON {}:{}({}) CALLED FROM {}@{} IN SCOPE {} {}(CODE {}) IN {} millis",
|
||||||
context.configuration().name(),context.configuration().serviceClass(), InnerMethodName.instance.get(),
|
appContext.configuration().name(), appContext.configuration().group(),
|
||||||
caller, callerIp, ScopeProvider.instance.get(), success?"SUCCEDED":"FAILED", e.response().getStatus(), System.currentTimeMillis()-startCallThreadLocal.get());
|
InnerMethodName.get(), caller, callerIp, context, success ? "SUCCEDED" : "FAILED",
|
||||||
|
e.response().getStatus(), durationInMillis);
|
||||||
|
|
||||||
|
} catch (Exception e1) {
|
||||||
|
log.error("error on accounting", e);
|
||||||
|
throw e1;
|
||||||
|
} finally {
|
||||||
startCallThreadLocal.remove();
|
startCallThreadLocal.remove();
|
||||||
InnerMethodName.instance.reset();
|
InnerMethodName.reset();
|
||||||
if (resetScope)
|
|
||||||
ScopeProvider.instance.reset();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void generateAccounting(String caller, String callerQualifier, String remoteHost, boolean success, ApplicationContext context){
|
}
|
||||||
AccountingPersistenceFactory.setFallbackLocation(context.container().persistence().location());
|
|
||||||
|
void generateAccounting(String caller, String callerQualifier, String remoteHost, boolean success,
|
||||||
|
String gcubeContext, ApplicationContext appContext) {
|
||||||
|
AccountingPersistenceFactory
|
||||||
|
.setFallbackLocation(appContext.container().configuration().accountingFallbackLocation());
|
||||||
AccountingPersistence persistence = AccountingPersistenceFactory.getPersistence();
|
AccountingPersistence persistence = AccountingPersistenceFactory.getPersistence();
|
||||||
ServiceUsageRecord serviceUsageRecord = new ServiceUsageRecord();
|
ServiceUsageRecord serviceUsageRecord = new ServiceUsageRecord();
|
||||||
try {
|
try {
|
||||||
|
|
||||||
serviceUsageRecord.setConsumerId(caller);
|
serviceUsageRecord.setConsumerId(caller);
|
||||||
serviceUsageRecord.setCallerQualifier(callerQualifier);
|
serviceUsageRecord.setCallerQualifier(callerQualifier);
|
||||||
serviceUsageRecord.setScope(ScopeProvider.instance.get());
|
serviceUsageRecord.setScope(gcubeContext);
|
||||||
serviceUsageRecord.setServiceClass(context.configuration().serviceClass());
|
serviceUsageRecord.setServiceClass(appContext.configuration().group());
|
||||||
serviceUsageRecord.setServiceName(context.configuration().name());
|
serviceUsageRecord.setServiceName(appContext.configuration().name());
|
||||||
|
|
||||||
serviceUsageRecord.setHost(context.container().configuration().hostname()+":"+context.container().configuration().port());
|
serviceUsageRecord.setHost(appContext.container().configuration().hostname() + ":"
|
||||||
serviceUsageRecord.setCalledMethod(InnerMethodName.instance.get());
|
+ appContext.container().configuration().port());
|
||||||
|
serviceUsageRecord.setCalledMethod(InnerMethodName.get());
|
||||||
serviceUsageRecord.setCallerHost(remoteHost);
|
serviceUsageRecord.setCallerHost(remoteHost);
|
||||||
serviceUsageRecord.setOperationResult(success ? OperationResult.SUCCESS : OperationResult.FAILED);
|
serviceUsageRecord.setOperationResult(success ? OperationResult.SUCCESS : OperationResult.FAILED);
|
||||||
serviceUsageRecord.setDuration(System.currentTimeMillis() - startCallThreadLocal.get());
|
serviceUsageRecord.setDuration(System.currentTimeMillis() - startCallThreadLocal.get());
|
||||||
|
@ -110,11 +131,17 @@ public class RequestAccounting extends RequestHandler {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String getContext(ApplicationContext appContext) {
|
||||||
|
String infrastructure = appContext.container().configuration().infrastructure();
|
||||||
|
String context = "/" + infrastructure;
|
||||||
|
if (SecretManagerProvider.get() != null)
|
||||||
|
context = SecretManagerProvider.get().getContext();
|
||||||
|
return context;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return getName();
|
return getName();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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());
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,6 +1,6 @@
|
||||||
package org.gcube.smartgears.handlers.application.request;
|
package org.gcube.smartgears.handlers.application.request;
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -0,0 +1,48 @@
|
||||||
|
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) {
|
||||||
|
try {
|
||||||
|
String statusCode = Integer.toString(e.response().getStatus());
|
||||||
|
Metrics.timer(HTTP_REQUEST_METRICS_NAME, "status", statusCode).record(Duration.ofMillis(System.currentTimeMillis() - startCallThreadLocal.get()));
|
||||||
|
startCallThreadLocal.remove();
|
||||||
|
}catch(Throwable t) {
|
||||||
|
log.warn("error setting Metrics",t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,47 +1,33 @@
|
||||||
package org.gcube.smartgears.handlers.application.request;
|
package org.gcube.smartgears.handlers.application.request;
|
||||||
|
|
||||||
import static org.gcube.common.authorization.client.Constants.authorizationService;
|
|
||||||
import static org.gcube.smartgears.handlers.application.request.RequestError.application_failed_error;
|
import static org.gcube.smartgears.handlers.application.request.RequestError.application_failed_error;
|
||||||
import static org.gcube.smartgears.handlers.application.request.RequestError.application_unavailable_error;
|
import static org.gcube.smartgears.handlers.application.request.RequestError.application_unavailable_error;
|
||||||
import static org.gcube.smartgears.handlers.application.request.RequestError.invalid_request_error;
|
import static org.gcube.smartgears.handlers.application.request.RequestError.invalid_request_error;
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Objects;
|
||||||
import java.util.List;
|
import java.util.Set;
|
||||||
|
|
||||||
import javax.xml.bind.annotation.XmlAttribute;
|
import org.gcube.common.security.ContextBean;
|
||||||
import javax.xml.bind.annotation.XmlRootElement;
|
import org.gcube.common.security.ContextBean.Type;
|
||||||
|
import org.gcube.common.security.providers.SecretManagerProvider;
|
||||||
import org.gcube.common.authorization.library.PolicyUtils;
|
import org.gcube.common.security.secrets.Secret;
|
||||||
import org.gcube.common.authorization.library.policies.Policy;
|
|
||||||
import org.gcube.common.authorization.library.policies.User2ServicePolicy;
|
|
||||||
import org.gcube.common.authorization.library.policies.UserEntity;
|
|
||||||
import org.gcube.common.authorization.library.provider.AccessTokenProvider;
|
|
||||||
import org.gcube.common.authorization.library.provider.AuthorizationProvider;
|
|
||||||
import org.gcube.common.authorization.library.provider.SecurityTokenProvider;
|
|
||||||
import org.gcube.common.authorization.library.provider.ServiceIdentifier;
|
|
||||||
import org.gcube.common.scope.api.ScopeProvider;
|
|
||||||
import org.gcube.common.scope.impl.ScopeBean;
|
|
||||||
import org.gcube.common.scope.impl.ScopeBean.Type;
|
|
||||||
import org.gcube.smartgears.Constants;
|
import org.gcube.smartgears.Constants;
|
||||||
import org.gcube.smartgears.configuration.Mode;
|
import org.gcube.smartgears.configuration.Mode;
|
||||||
import org.gcube.smartgears.configuration.container.ContainerConfiguration;
|
import org.gcube.smartgears.configuration.container.ContainerConfiguration;
|
||||||
import org.gcube.smartgears.context.application.ApplicationContext;
|
import org.gcube.smartgears.context.application.ApplicationContext;
|
||||||
import org.gcube.smartgears.handlers.application.RequestEvent;
|
import org.gcube.smartgears.handlers.application.RequestEvent;
|
||||||
import org.gcube.smartgears.handlers.application.RequestHandler;
|
import org.gcube.smartgears.handlers.application.RequestHandler;
|
||||||
import org.gcube.smartgears.utils.Utils;
|
import org.gcube.smartgears.handlers.application.ResponseEvent;
|
||||||
|
import org.gcube.smartgears.security.secrets.SecretFactory;
|
||||||
|
import org.gcube.smartgears.security.secrets.exceptions.SecretNotFoundException;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
@XmlRootElement(name = Constants.request_validation)
|
|
||||||
public class RequestValidator extends RequestHandler {
|
public class RequestValidator extends RequestHandler {
|
||||||
|
|
||||||
@XmlAttribute(required=false, name="oauth")
|
|
||||||
@Deprecated
|
|
||||||
boolean oauthCompatibility = false;
|
|
||||||
|
|
||||||
private static Logger log = LoggerFactory.getLogger(RequestValidator.class);
|
private static Logger log = LoggerFactory.getLogger(RequestValidator.class);
|
||||||
|
|
||||||
private ApplicationContext context;
|
private ApplicationContext appContext;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getName() {
|
public String getName() {
|
||||||
|
@ -53,27 +39,30 @@ public class RequestValidator extends RequestHandler {
|
||||||
|
|
||||||
log.trace("executing request validator ON REQUEST");
|
log.trace("executing request validator ON REQUEST");
|
||||||
|
|
||||||
log.trace("accessToken is null? {} \nGcubeToken is null ? {} \nscope rpvideris null? {}",
|
appContext = call.context();
|
||||||
AccessTokenProvider.instance.get()==null,
|
|
||||||
SecurityTokenProvider.instance.get()==null,
|
|
||||||
ScopeProvider.instance.get()==null);
|
|
||||||
|
|
||||||
context = call.context();
|
SecretManagerProvider.set(getSecret(call));
|
||||||
|
|
||||||
validateAgainstLifecycle(call);
|
validateAgainstLifecycle(call);
|
||||||
|
|
||||||
rejectUnauthorizedCalls(call);
|
rejectUnauthorizedCalls(call);
|
||||||
|
|
||||||
if (context.container().configuration().mode()!=Mode.offline) {
|
if (appContext.container().configuration().mode()!=Mode.offline) {
|
||||||
validateScopeCall();
|
validateScopeCall();
|
||||||
validatePolicy(ScopeProvider.instance.get(), call);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handleResponse(ResponseEvent e) {
|
||||||
|
log.debug("resetting all the Thread local for this call.");
|
||||||
|
SecretManagerProvider.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private void validateAgainstLifecycle(RequestEvent call) {
|
private void validateAgainstLifecycle(RequestEvent call) {
|
||||||
|
|
||||||
switch(context.lifecycle().state()) {
|
switch(appContext.lifecycle().state()) {
|
||||||
|
|
||||||
case stopped :
|
case stopped :
|
||||||
application_unavailable_error.fire(); break;
|
application_unavailable_error.fire(); break;
|
||||||
|
@ -85,36 +74,36 @@ public class RequestValidator extends RequestHandler {
|
||||||
//nothing to do, but avoids warnings
|
//nothing to do, but avoids warnings
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void validateScopeCall() {
|
private void validateScopeCall() {
|
||||||
|
|
||||||
String scope = ScopeProvider.instance.get();
|
String context = SecretManagerProvider.get().getContext();
|
||||||
|
|
||||||
if (scope == null) {
|
if (context == null) {
|
||||||
log.warn("rejecting unscoped call to {}",context.name());
|
log.warn("rejecting unscoped call to {}",appContext.name());
|
||||||
invalid_request_error.fire("call is unscoped");
|
invalid_request_error.fire("call is unscoped");
|
||||||
}
|
}
|
||||||
|
|
||||||
ScopeBean bean = new ScopeBean(scope);
|
ContextBean bean = new ContextBean(context);
|
||||||
|
|
||||||
ContainerConfiguration conf = context.container().configuration();
|
ContainerConfiguration conf = appContext.container().configuration();
|
||||||
if (!conf.allowedContexts().contains(scope) &&
|
Set<String> allowedContexts =appContext.authorizationProvider().getContexts();
|
||||||
!(conf.authorizeChildrenContext() && bean.is(Type.VRE) && conf.allowedContexts().contains(bean.enclosingScope().toString()) ) ) {
|
if (!allowedContexts.contains(context) &&
|
||||||
log.warn("rejecting call to {} in invalid context {}, allowed context are {}",context.name(),scope,context.container().configuration().allowedContexts());
|
!(conf.authorizeChildrenContext() && bean.is(Type.VRE)
|
||||||
invalid_request_error.fire(context.name()+" cannot be called in scope "+scope);
|
&& allowedContexts.contains(bean.enclosingScope().toString()) ) ) {
|
||||||
|
log.warn("rejecting call to {} in invalid context {}, allowed context are {}",appContext.name(),context,allowedContexts);
|
||||||
|
invalid_request_error.fire(appContext.name()+" cannot be called in scope "+context);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void rejectUnauthorizedCalls(RequestEvent call){
|
private void rejectUnauthorizedCalls(RequestEvent call){
|
||||||
|
|
||||||
String token = SecurityTokenProvider.instance.get();
|
Secret secret = SecretManagerProvider.get();
|
||||||
String accessToken = AccessTokenProvider.instance.get();
|
|
||||||
|
|
||||||
if (token == null && accessToken==null){
|
if (secret == null){
|
||||||
log.warn("rejecting call to {}, authorization required",context.name(),token);
|
log.warn("rejecting call to {}, authorization required",appContext.name());
|
||||||
RequestError.request_not_authorized_error.fire(context.name()+": authorization required");
|
RequestError.request_not_authorized_error.fire(appContext.name()+": authorization required");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -123,45 +112,32 @@ public class RequestValidator extends RequestHandler {
|
||||||
return getName();
|
return getName();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void validatePolicy(String scope, RequestEvent call){
|
|
||||||
log.info("accessing policy validator in scope {} ", scope);
|
|
||||||
|
|
||||||
ServiceIdentifier serviceIdentifier = Utils.getServiceInfo(call.context()).getServiceIdentifier();
|
private Secret getSecret(RequestEvent call){
|
||||||
|
|
||||||
String previousToken = SecurityTokenProvider.instance.get();
|
Secret secret = null;
|
||||||
|
for (SecretFactory<? extends Secret> factory: call.context().allowedSecretFactories()) {
|
||||||
try {
|
try {
|
||||||
String serviceToken = context.configuration().startTokens().stream().findFirst().get();
|
secret = factory.create(call.request());
|
||||||
SecurityTokenProvider.instance.set(serviceToken);
|
break;
|
||||||
String callerId = AuthorizationProvider.instance.get().getClient().getId();
|
} catch (SecretNotFoundException e) {
|
||||||
|
log.info("authorization for secret {} not found", factory.getSecretClass().getName());
|
||||||
List<Policy> policies = Collections.emptyList();
|
} catch (Throwable t) {
|
||||||
try {
|
log.warn("generic error creating secret {}", factory.getSecretClass().getName(), t);
|
||||||
policies = authorizationService().getPolicies(scope);
|
|
||||||
}catch (Exception e) {
|
|
||||||
log.error("error contacting authorization services for policies");
|
|
||||||
}
|
|
||||||
|
|
||||||
for (Policy policy: policies) {
|
|
||||||
log.debug("policy: {}", policy.getPolicyAsString() );
|
|
||||||
|
|
||||||
if (PolicyUtils.isPolicyValidForClient(policy.getServiceAccess(), serviceIdentifier )) {
|
|
||||||
boolean toReject = false;
|
|
||||||
UserEntity entity = (((User2ServicePolicy) policy).getEntity());
|
|
||||||
if (entity.getIdentifier()!=null)
|
|
||||||
toReject = entity.getIdentifier().equals(callerId);
|
|
||||||
else if (entity.getExcludes().isEmpty())
|
|
||||||
toReject = true;
|
|
||||||
else toReject = !entity.getExcludes().contains(callerId);
|
|
||||||
if (toReject) {
|
|
||||||
log.error("rejecting call to {} : {} is not allowed to contact the service ",context.name(), callerId);
|
|
||||||
RequestError.request_not_authorized_error.fire("rejecting call to "+context.name()+" for polices: "+callerId+" is not allowed to contact the service: "+serviceIdentifier.getServiceName() );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}finally {
|
|
||||||
SecurityTokenProvider.instance.set(previousToken);
|
if (Objects.isNull(secret))
|
||||||
}
|
RequestError.request_not_authorized_error.fire("call not authorized");
|
||||||
|
|
||||||
|
if (!secret.isValid())
|
||||||
|
RequestError.request_not_authorized_error.fire("authorization with secret "+secret.getClass().getSimpleName()+": token not valid ");
|
||||||
|
|
||||||
|
if (call.context().container().configuration().checkTokenExpiration() && secret.isExpired())
|
||||||
|
RequestError.request_not_authorized_error.fire("authorization with secret "+secret.getClass().getSimpleName()+": token expired ");
|
||||||
|
|
||||||
|
return secret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -5,8 +5,6 @@ package org.gcube.smartgears.handlers.container.lifecycle;
|
||||||
|
|
||||||
import static org.gcube.smartgears.Constants.accounting_management;
|
import static org.gcube.smartgears.Constants.accounting_management;
|
||||||
|
|
||||||
import javax.xml.bind.annotation.XmlRootElement;
|
|
||||||
|
|
||||||
import org.gcube.accounting.persistence.AccountingPersistenceFactory;
|
import org.gcube.accounting.persistence.AccountingPersistenceFactory;
|
||||||
import org.gcube.smartgears.handlers.container.ContainerHandler;
|
import org.gcube.smartgears.handlers.container.ContainerHandler;
|
||||||
import org.gcube.smartgears.handlers.container.ContainerLifecycleEvent;
|
import org.gcube.smartgears.handlers.container.ContainerLifecycleEvent;
|
||||||
|
@ -16,7 +14,6 @@ import org.slf4j.LoggerFactory;
|
||||||
/**
|
/**
|
||||||
* @author Luca Frosini (ISTI - CNR)
|
* @author Luca Frosini (ISTI - CNR)
|
||||||
*/
|
*/
|
||||||
@XmlRootElement(name = accounting_management)
|
|
||||||
public class AccountingManager extends ContainerHandler {
|
public class AccountingManager extends ContainerHandler {
|
||||||
|
|
||||||
private static Logger logger = LoggerFactory.getLogger(AccountingManager.class);
|
private static Logger logger = LoggerFactory.getLogger(AccountingManager.class);
|
||||||
|
|
|
@ -0,0 +1,218 @@
|
||||||
|
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.changed;
|
||||||
|
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.managers.ContextEvents;
|
||||||
|
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 -- contains published prop? {}",context.properties().contains(PUBLISHED_PROP));
|
||||||
|
// if we've failed before first publication do not try to publish
|
||||||
|
// (we may well have failed there)
|
||||||
|
if (context.lifecycle().state() != ContainerState.failed) {
|
||||||
|
if (!context.properties().contains(PUBLISHED_PROP)) {
|
||||||
|
context.properties().add(new Property(PUBLISHED_PROP, true));
|
||||||
|
log.info("publishing container for the first time");
|
||||||
|
|
||||||
|
publishers.parallelStream().forEach(p -> {
|
||||||
|
try {
|
||||||
|
p.create(context, context.authorizationProvider().getContexts());
|
||||||
|
} catch (Throwable e) {
|
||||||
|
log.error(
|
||||||
|
"cannot publish container for first time with publisher type {} (see details)",
|
||||||
|
p.getClass().getCanonicalName(), e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else
|
||||||
|
publishers.parallelStream().forEach(p -> {
|
||||||
|
try {
|
||||||
|
p.update(context);
|
||||||
|
} catch (Throwable e) {
|
||||||
|
log.error("cannot publish container with publisher type {} (see details)",
|
||||||
|
p.getClass().getCanonicalName(), e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Observes(value = ContextEvents.ADD_CONTEXT_TO_CONTAINER)
|
||||||
|
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 = ContextEvents.REMOVE_CONTEXT_FROM_CONTAINER)
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,93 @@
|
||||||
|
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.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Luca Frosini (ISTI-CNR)
|
||||||
|
*/
|
||||||
|
public class LinuxDistributionInfo {
|
||||||
|
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(LinuxDistributionInfo.class);
|
||||||
|
|
||||||
|
public static final String LSB_RELEASE_COMMAND = "lsb_release -a";
|
||||||
|
public static final String OS_RELEASE_FILE_PATH = "/etc/os-release";
|
||||||
|
|
||||||
|
protected Map<String, String> info;
|
||||||
|
|
||||||
|
protected Map<String, String> getInfoViaLsbReleaseCommand() throws IOException {
|
||||||
|
logger.trace("Going to exec {}", LSB_RELEASE_COMMAND);
|
||||||
|
Process process = Runtime.getRuntime().exec(LSB_RELEASE_COMMAND);
|
||||||
|
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
|
||||||
|
Map<String, String> map = parseBufferedReader(bufferedReader);
|
||||||
|
bufferedReader.close();
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<String, String> parseBufferedReader(BufferedReader bufferedReader) throws IOException {
|
||||||
|
Map<String, String> map = new HashMap<>();
|
||||||
|
String line = "";
|
||||||
|
while ((line = bufferedReader.readLine()) != null) {
|
||||||
|
String[] nameValue = parseLine(line);
|
||||||
|
map.put(nameValue[0], nameValue[1]);
|
||||||
|
}
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String[] parseLine(String line) {
|
||||||
|
String[] splitted = line.split("=");
|
||||||
|
if (splitted.length < 2) {
|
||||||
|
splitted = line.split(":");
|
||||||
|
}
|
||||||
|
String[] ret = new String[2];
|
||||||
|
ret[0] = splitted[0].trim();
|
||||||
|
ret[1] = splitted[1].trim().replace("\"", "");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<String, String> getInfoViaFile(File file) throws IOException {
|
||||||
|
logger.trace("Going to read file {}", file.getAbsolutePath());
|
||||||
|
BufferedReader bufferedReader = new BufferedReader(new FileReader(file));
|
||||||
|
Map<String, String> map = parseBufferedReader(bufferedReader);
|
||||||
|
bufferedReader.close();
|
||||||
|
return map;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Map<String, String> getInfoViaOsReleaseFile() throws IOException {
|
||||||
|
File osReleaseFile = new File(OS_RELEASE_FILE_PATH);
|
||||||
|
return getInfoViaFile(osReleaseFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<String, String> retriveInfo() {
|
||||||
|
try {
|
||||||
|
return getInfoViaLsbReleaseCommand();
|
||||||
|
} catch (IOException e) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
return getInfoViaOsReleaseFile();
|
||||||
|
}catch (IOException e) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, String> getInfo() {
|
||||||
|
if (info == null) {
|
||||||
|
info = retriveInfo();
|
||||||
|
}
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,366 +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));
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
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.trace("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().error(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().error("no contexts are defined for the client id provided").build();
|
||||||
|
return HealthCheckResponse.builder(CHECK_NAME).up().info(String.format("running contexts are %s", contexts)).build();
|
||||||
|
}catch (Exception e) {
|
||||||
|
return HealthCheckResponse.builder(CHECK_NAME).down().error(e.getMessage()).build();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -12,36 +12,27 @@ import static org.gcube.smartgears.provider.ProviderFactory.provider;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
import java.io.ObjectOutputStream;
|
import java.io.ObjectOutputStream;
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
import javax.servlet.FilterRegistration;
|
import jakarta.servlet.FilterRegistration;
|
||||||
import javax.servlet.ServletContext;
|
import jakarta.servlet.ServletContext;
|
||||||
import javax.servlet.ServletContextEvent;
|
import jakarta.servlet.ServletContextEvent;
|
||||||
import javax.servlet.ServletContextListener;
|
import jakarta.servlet.ServletContextListener;
|
||||||
import javax.servlet.ServletRegistration;
|
import jakarta.servlet.ServletRegistration;
|
||||||
|
|
||||||
import org.gcube.common.authorization.client.proxy.AuthorizationProxy;
|
|
||||||
import org.gcube.common.authorization.library.provider.SecurityTokenProvider;
|
|
||||||
import org.gcube.common.events.Observes;
|
import org.gcube.common.events.Observes;
|
||||||
import org.gcube.smartgears.Constants;
|
|
||||||
import org.gcube.smartgears.configuration.Mode;
|
|
||||||
import org.gcube.smartgears.configuration.application.ApplicationExtensions;
|
|
||||||
import org.gcube.smartgears.configuration.application.ApplicationHandlers;
|
import org.gcube.smartgears.configuration.application.ApplicationHandlers;
|
||||||
import org.gcube.smartgears.context.application.ApplicationContext;
|
import org.gcube.smartgears.context.application.ApplicationContext;
|
||||||
import org.gcube.smartgears.context.container.ContainerContext;
|
import org.gcube.smartgears.context.container.ContainerContext;
|
||||||
import org.gcube.smartgears.extensions.ApplicationExtension;
|
import org.gcube.smartgears.extensions.ApplicationExtension;
|
||||||
import org.gcube.smartgears.extensions.RequestExceptionBarrier;
|
import org.gcube.smartgears.extensions.RequestExceptionBarrier;
|
||||||
import org.gcube.smartgears.handlers.ProfileEvents;
|
|
||||||
import org.gcube.smartgears.handlers.application.ApplicationLifecycleEvent;
|
import org.gcube.smartgears.handlers.application.ApplicationLifecycleEvent;
|
||||||
import org.gcube.smartgears.handlers.application.ApplicationLifecycleHandler;
|
import org.gcube.smartgears.handlers.application.ApplicationLifecycleHandler;
|
||||||
import org.gcube.smartgears.handlers.application.ApplicationPipeline;
|
import org.gcube.smartgears.handlers.application.ApplicationPipeline;
|
||||||
import org.gcube.smartgears.handlers.application.RequestHandler;
|
import org.gcube.smartgears.handlers.application.RequestHandler;
|
||||||
import org.gcube.smartgears.lifecycle.application.ApplicationLifecycle;
|
import org.gcube.smartgears.lifecycle.application.ApplicationLifecycle;
|
||||||
import org.gcube.smartgears.lifecycle.container.ContainerLifecycle;
|
import org.gcube.smartgears.lifecycle.container.ContainerLifecycle;
|
||||||
import org.gcube.smartgears.utils.Utils;
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
@ -59,6 +50,8 @@ public class ApplicationManager {
|
||||||
|
|
||||||
private ApplicationContext context;
|
private ApplicationContext context;
|
||||||
|
|
||||||
|
private List<ApplicationExtension> extensions;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Starts application management.
|
* Starts application management.
|
||||||
*
|
*
|
||||||
|
@ -75,18 +68,8 @@ public class ApplicationManager {
|
||||||
for (Entry<String,? extends ServletRegistration> servlet : application.getServletRegistrations().entrySet())
|
for (Entry<String,? extends ServletRegistration> servlet : application.getServletRegistrations().entrySet())
|
||||||
log.trace("servlet {} : {} {} ", application.getServletContextName(),servlet.getKey(), servlet.getValue().getMappings());
|
log.trace("servlet {} : {} {} ", application.getServletContextName(),servlet.getKey(), servlet.getValue().getMappings());
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* if (context.configuration().secure() &&
|
|
||||||
container.configuration().securePort()==null)
|
|
||||||
throw new IllegalStateException(
|
|
||||||
String.format("Application %s cannot be managed because is declared as secure without a secure connector port declared in the container", context.application().getContextPath()));
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (context.container().configuration().mode()!=Mode.offline) {
|
|
||||||
context.configuration().startTokens(generateTokensForApplication(container).stream().collect(Collectors.toSet()));
|
|
||||||
context.configuration().validate();
|
context.configuration().validate();
|
||||||
}
|
|
||||||
saveApplicationState();
|
saveApplicationState();
|
||||||
|
|
||||||
// make context available to application in case it is gcube-aware
|
// make context available to application in case it is gcube-aware
|
||||||
|
@ -96,13 +79,8 @@ public class ApplicationManager {
|
||||||
registerObservers();
|
registerObservers();
|
||||||
|
|
||||||
ApplicationHandlers handlers = provider().handlersFor(context);
|
ApplicationHandlers handlers = provider().handlersFor(context);
|
||||||
handlers.validate();
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
ApplicationExtensions extensions = provider().extensionsFor(context);
|
|
||||||
extensions.validate();
|
|
||||||
|
|
||||||
List<ApplicationLifecycleHandler> lifecycleHandlers = handlers.lifecycleHandlers();
|
List<ApplicationLifecycleHandler> lifecycleHandlers = handlers.lifecycleHandlers();
|
||||||
List<RequestHandler> requestHandlers = handlers.requestHandlers();
|
List<RequestHandler> requestHandlers = handlers.requestHandlers();
|
||||||
|
|
||||||
|
@ -111,11 +89,12 @@ public class ApplicationManager {
|
||||||
log.trace("managing {} requests with {}", context.name(), requestHandlers);
|
log.trace("managing {} requests with {}", context.name(), requestHandlers);
|
||||||
log.trace("extending {} API with {}", context.name(), extensions);
|
log.trace("extending {} API with {}", context.name(), extensions);
|
||||||
|
|
||||||
|
extensions = provider().extensionsFor(context);
|
||||||
// order is important here: first add APIs
|
// order is important here: first add APIs
|
||||||
register(extensions);
|
registerExtension(extensions);
|
||||||
|
|
||||||
// then intercept them all
|
// then intercept them all
|
||||||
register(requestHandlers);
|
registerHandlersAsFilter(requestHandlers);
|
||||||
|
|
||||||
// start lifecycle management
|
// start lifecycle management
|
||||||
start(lifecycleHandlers);
|
start(lifecycleHandlers);
|
||||||
|
@ -123,6 +102,7 @@ public class ApplicationManager {
|
||||||
//adding the context name to the configuration
|
//adding the context name to the configuration
|
||||||
context.configuration().context(application.getContextPath());
|
context.configuration().context(application.getContextPath());
|
||||||
|
|
||||||
|
|
||||||
// we're in business
|
// we're in business
|
||||||
context.lifecycle().moveTo(active);
|
context.lifecycle().moveTo(active);
|
||||||
|
|
||||||
|
@ -143,43 +123,8 @@ public class ApplicationManager {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<String> generateTokensForApplication(ContainerContext container){
|
|
||||||
log.info("generating token for app {}",context.configuration().name());
|
|
||||||
|
|
||||||
SecurityTokenProvider.instance.set(container.configuration().startTokens().get(0));
|
|
||||||
try {
|
|
||||||
AuthorizationProxy authProxy = provider().authorizationProxy();
|
|
||||||
try {
|
|
||||||
return authProxy.generateServiceToken(Utils.getServiceInfo(context), container.configuration().startTokens());
|
|
||||||
}catch (Exception e) {
|
|
||||||
log.error("error generating service token",e);
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new RuntimeException("error contacting authorization service",e);
|
|
||||||
} finally{
|
|
||||||
SecurityTokenProvider.instance.reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private String generateApplicationToken(String containerToken, AuthorizationProxy authProxy){
|
|
||||||
SecurityTokenProvider.instance.set(containerToken);
|
|
||||||
try {
|
|
||||||
log.info("generating token for app {} with container token {} ",context.configuration().name(), containerToken);
|
|
||||||
return authProxy.generateServiceToken(Utils.getServiceInfo(context));
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new RuntimeException("error contacting authorization service",e);
|
|
||||||
} finally{
|
|
||||||
SecurityTokenProvider.instance.reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private void saveApplicationState() {
|
private void saveApplicationState() {
|
||||||
File file = context.configuration().persistence().file(profile_file_path);
|
File file = context.persistence().file(profile_file_path);
|
||||||
try(ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(file))){
|
try(ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(file))){
|
||||||
oos.writeObject(context.id());
|
oos.writeObject(context.id());
|
||||||
}catch (Exception e) {
|
}catch (Exception e) {
|
||||||
|
@ -206,6 +151,9 @@ public class ApplicationManager {
|
||||||
|
|
||||||
context.events().fire(context, ApplicationLifecycle.stop);
|
context.events().fire(context, ApplicationLifecycle.stop);
|
||||||
|
|
||||||
|
if (extensions != null)
|
||||||
|
unregister(extensions);
|
||||||
|
|
||||||
stopLifecycleHandlers();
|
stopLifecycleHandlers();
|
||||||
|
|
||||||
log.info("stopping application events for {}", context.name());
|
log.info("stopping application events for {}", context.name());
|
||||||
|
@ -219,38 +167,25 @@ public class ApplicationManager {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void register(List<RequestHandler> rqHandlers) {
|
private void registerHandlersAsFilter(List<RequestHandler> rqHandlers) {
|
||||||
|
|
||||||
ServletContext app = context.application();
|
ServletContext app = context.application();
|
||||||
|
|
||||||
// attach filters based on request pipeline to each servlet
|
String appName = app.getContextPath().replace("/", "");
|
||||||
Collection<? extends ServletRegistration> servlets = app.getServletRegistrations().values();
|
|
||||||
|
|
||||||
for (ServletRegistration servlet : servlets) {
|
RequestManager requestFilter = new RequestManager(context, appName, rqHandlers);
|
||||||
|
|
||||||
String name = servlet.getName();
|
FilterRegistration.Dynamic filter = app.addFilter(appName + "-filter", requestFilter);
|
||||||
|
|
||||||
if (name.equals("default") || name.equals("jsp")) // skip page-resolving servlets
|
filter.addMappingForUrlPatterns(null, false, "/*");
|
||||||
continue;
|
|
||||||
|
|
||||||
for (String mapping : servlet.getMappings()) {
|
|
||||||
|
|
||||||
RequestManager requestFilter = new RequestManager(context, name, rqHandlers);
|
|
||||||
|
|
||||||
FilterRegistration.Dynamic filter = app.addFilter(name + "-filter-"+mapping.replaceAll("/", ""), requestFilter);
|
|
||||||
|
|
||||||
log.trace("filter {} for requestfilter {} in contextPath {} is null ?? {} ",name ,requestFilter, mapping, (filter==null));
|
|
||||||
|
|
||||||
filter.addMappingForUrlPatterns(null, false, mapping);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void register(ApplicationExtensions extensions) {
|
private void registerExtension(List<ApplicationExtension> extensions) {
|
||||||
|
|
||||||
ServletContext application = context.application();
|
ServletContext application = context.application();
|
||||||
|
|
||||||
for (ApplicationExtension extension : extensions.extensions())
|
for (ApplicationExtension extension : extensions)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
|
@ -283,6 +218,14 @@ public class ApplicationManager {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void unregister(List<ApplicationExtension> extensions) {
|
||||||
|
|
||||||
|
for (ApplicationExtension extension : extensions)
|
||||||
|
extension.stop();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private void start(List<ApplicationLifecycleHandler> handlers) {
|
private void start(List<ApplicationLifecycleHandler> handlers) {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -320,28 +263,6 @@ public class ApplicationManager {
|
||||||
log.warn("cannot stop {} after container has stopped", context.name());
|
log.warn("cannot stop {} after container has stopped", context.name());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Observes(value = ContextEvents.ADD_TOKEN_TO_APPLICATION, kind = critical)
|
|
||||||
void onAddToken(String containerToken) {
|
|
||||||
log.trace("event add received with token {} ",containerToken);
|
|
||||||
String appToken = generateApplicationToken(containerToken, provider().authorizationProxy());
|
|
||||||
context.configuration().startTokens().add(appToken);
|
|
||||||
log.trace("app token created : {} ", appToken);
|
|
||||||
context.events().fire(appToken, ProfileEvents.addToContext);
|
|
||||||
context.events().fire(appToken, Constants.token_registered);
|
|
||||||
saveApplicationState();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Observes(value = ContextEvents.REMOVE_TOKEN_FROM_APPLICATION, kind = critical)
|
|
||||||
void onRemoveToken(String containerToken) {
|
|
||||||
log.trace("event remove received with token {} ",containerToken);
|
|
||||||
String appToken = generateApplicationToken(containerToken, provider().authorizationProxy());
|
|
||||||
context.configuration().startTokens().remove(appToken);
|
|
||||||
log.trace("app token removed : {} ", appToken);
|
|
||||||
context.events().fire(appToken, ProfileEvents.removeFromContext);
|
|
||||||
context.events().fire(appToken, Constants.token_removed);
|
|
||||||
saveApplicationState();
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
context.container().events().subscribe(observer);
|
context.container().events().subscribe(observer);
|
||||||
|
@ -352,7 +273,8 @@ public class ApplicationManager {
|
||||||
@Override
|
@Override
|
||||||
public void contextInitialized(ServletContextEvent sce) {
|
public void contextInitialized(ServletContextEvent sce) {
|
||||||
log.info("initilizing context {} ",context.name());
|
log.info("initilizing context {} ",context.name());
|
||||||
context.events().fire(context.application().getContextPath(), ApplicationLifecycle.activation);
|
|
||||||
|
context.events().fire(context, ApplicationLifecycle.activation);
|
||||||
log.info("webApp {} initialized ",context.name());
|
log.info("webApp {} initialized ",context.name());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,22 +10,14 @@ import static org.gcube.smartgears.provider.ProviderFactory.provider;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
import java.io.ObjectOutputStream;
|
import java.io.ObjectOutputStream;
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import org.gcube.common.authorization.client.exceptions.ObjectNotFound;
|
|
||||||
import org.gcube.common.authorization.client.proxy.AuthorizationProxy;
|
|
||||||
import org.gcube.common.authorization.library.AuthorizationEntry;
|
|
||||||
import org.gcube.common.authorization.library.provider.ClientInfo;
|
|
||||||
import org.gcube.common.authorization.library.provider.ContainerInfo;
|
|
||||||
import org.gcube.common.events.Observes;
|
import org.gcube.common.events.Observes;
|
||||||
import org.gcube.common.events.Observes.Kind;
|
import org.gcube.common.events.Observes.Kind;
|
||||||
import org.gcube.smartgears.configuration.Mode;
|
import org.gcube.smartgears.configuration.Mode;
|
||||||
import org.gcube.smartgears.configuration.container.ContainerHandlers;
|
|
||||||
import org.gcube.smartgears.context.application.ApplicationContext;
|
import org.gcube.smartgears.context.application.ApplicationContext;
|
||||||
import org.gcube.smartgears.context.container.ContainerContext;
|
import org.gcube.smartgears.context.container.ContainerContext;
|
||||||
import org.gcube.smartgears.handlers.ProfileEvents;
|
|
||||||
import org.gcube.smartgears.handlers.container.ContainerHandler;
|
import org.gcube.smartgears.handlers.container.ContainerHandler;
|
||||||
import org.gcube.smartgears.handlers.container.ContainerLifecycleEvent;
|
import org.gcube.smartgears.handlers.container.ContainerLifecycleEvent;
|
||||||
import org.gcube.smartgears.handlers.container.ContainerPipeline;
|
import org.gcube.smartgears.handlers.container.ContainerPipeline;
|
||||||
|
@ -47,8 +39,6 @@ public class ContainerManager {
|
||||||
|
|
||||||
public static ContainerManager instance = new ContainerManager();
|
public static ContainerManager instance = new ContainerManager();
|
||||||
|
|
||||||
private AuthorizationProxy authProvider = provider().authorizationProxy();
|
|
||||||
|
|
||||||
private ContainerContext context;
|
private ContainerContext context;
|
||||||
|
|
||||||
private ContainerPipeline pipeline;
|
private ContainerPipeline pipeline;
|
||||||
|
@ -70,21 +60,17 @@ public class ContainerManager {
|
||||||
|
|
||||||
saveContainerState();
|
saveContainerState();
|
||||||
|
|
||||||
ContainerHandlers handlers = provider().containerHandlers();
|
List<ContainerHandler> handlers = provider().containerHandlers();
|
||||||
|
|
||||||
log.trace("managing container lifecycle with {}", handlers.get());
|
log.trace("managing container lifecycle with {}", handlers);
|
||||||
|
|
||||||
startHandlers(handlers.get());
|
|
||||||
|
startHandlers(handlers);
|
||||||
|
|
||||||
context.lifecycle().moveTo(active);
|
context.lifecycle().moveTo(active);
|
||||||
|
|
||||||
log.trace("loading keys for starting token ...");
|
|
||||||
//loadKeyForToken(context.configuration().startTokens());
|
|
||||||
log.trace("keys loaded for starting token ...");
|
|
||||||
|
|
||||||
return context;
|
return context;
|
||||||
}
|
} catch (RuntimeException e) {
|
||||||
catch(RuntimeException e) {
|
|
||||||
|
|
||||||
log.error("cannot manage container (see cause)", e);
|
log.error("cannot manage container (see cause)", e);
|
||||||
|
|
||||||
|
@ -96,12 +82,10 @@ public class ContainerManager {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void saveContainerState() {
|
private void saveContainerState() {
|
||||||
File file = context.configuration().persistence().file(container_profile_file_path);
|
File file = context.persistenceWriter().file(container_profile_file_path);
|
||||||
try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(file))) {
|
try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(file))) {
|
||||||
oos.writeObject(context.id());
|
oos.writeObject(context.id());
|
||||||
oos.writeObject(context.configuration().startTokens());
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("error serializing cointainer state");
|
log.error("error serializing cointainer state");
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
|
@ -112,59 +96,24 @@ public class ContainerManager {
|
||||||
private void validateContainer(ContainerContext context) {
|
private void validateContainer(ContainerContext context) {
|
||||||
// List<String> tokensToRemove = new ArrayList<String>();
|
// List<String> tokensToRemove = new ArrayList<String>();
|
||||||
context.configuration().validate();
|
context.configuration().validate();
|
||||||
Set<String> foundContexts= new HashSet<String>();
|
Set<String> foundContexts;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
List<AuthorizationEntry> entries = authProvider.get(context.configuration().startTokens());
|
foundContexts = context.authorizationProvider().getContexts();
|
||||||
|
|
||||||
log.info("requesting auth on {} tokens returned {} entries", context.configuration().startTokens().size(),entries.size());
|
|
||||||
|
|
||||||
for (AuthorizationEntry entry : entries ) {
|
|
||||||
log.info("the container will be started in context {}",entry.getContext());
|
|
||||||
foundContexts.add(entry.getContext());
|
|
||||||
}
|
|
||||||
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("error contacting auth service on container",e);
|
log.error("error authorizing container", e);
|
||||||
|
throw new RuntimeException("error authorizing container, moving the container to failed", e);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (foundContexts.isEmpty()) {
|
if (foundContexts.isEmpty()) {
|
||||||
log.error("no valid starting token are specified, moving the container to failed");
|
log.error("no valid contexts found, moving the container to failed");
|
||||||
throw new RuntimeException("no valid starting token are specified");
|
throw new RuntimeException("no valid contexts found, moving the container to failed");
|
||||||
}
|
}
|
||||||
|
|
||||||
//context.configuration().startTokens().removeAll(tokensToRemove);
|
|
||||||
context.configuration().allowedContexts(foundContexts);
|
|
||||||
}
|
|
||||||
|
|
||||||
private String resolveTokenForAdd(Set<String> alreadyAddedContext, String token){
|
|
||||||
try {
|
|
||||||
AuthorizationEntry entry = authProvider.get(token);
|
|
||||||
ClientInfo info = entry.getClientInfo();
|
|
||||||
log.info("resolved authorization entry for container {}",entry);
|
|
||||||
if (alreadyAddedContext.contains(entry.getContext())){
|
|
||||||
log.warn("the token {} cannot be used, another token with the same context {} found ", entry.getContext());
|
|
||||||
} else if(!entry.getContext().startsWith("/"+context.configuration().infrastructure())){
|
|
||||||
log.warn("the token {} cannot be used, is not in the infrastructure {} of the container ", token,context.configuration().infrastructure());
|
|
||||||
}else if (!(info instanceof ContainerInfo)){
|
|
||||||
log.warn("the token {} cannot be used, is not for a container token ", token);
|
|
||||||
} else if (!((ContainerInfo)info).getHost().equals(context.configuration().hostname())
|
|
||||||
|| context.configuration().port()!=((ContainerInfo)info).getPort()){
|
|
||||||
log.warn("the token {} cannot be used, the client id {} resolved with the token is not the same of the one specified in this container ", token, info.getId());
|
|
||||||
} else
|
|
||||||
return entry.getContext();
|
|
||||||
}catch(ObjectNotFound onf){
|
|
||||||
log.error("token {} not valid", token);
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.error("error contacting authorization for token {}",token,e);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void manage(ApplicationContext app) {
|
public void manage(ApplicationContext app) {
|
||||||
|
|
||||||
app.events().subscribe(this);
|
app.events().subscribe(this);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Observes(value = { ApplicationLifecycle.failure, ApplicationLifecycle.stop }, kind = Kind.critical)
|
@Observes(value = { ApplicationLifecycle.failure, ApplicationLifecycle.stop }, kind = Kind.critical)
|
||||||
|
@ -172,42 +121,6 @@ public class ContainerManager {
|
||||||
context.lifecycle().tryMoveTo(ContainerState.partActive);
|
context.lifecycle().tryMoveTo(ContainerState.partActive);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Observes(value=ContextEvents.ADD_TOKEN_TO_CONTAINER,kind=Kind.critical)
|
|
||||||
void addToken(String token) {
|
|
||||||
log.trace("adding token {} to container", token);
|
|
||||||
String newContext;
|
|
||||||
if ((newContext = resolveTokenForAdd(context.configuration().allowedContexts(), token))!=null) {
|
|
||||||
context.configuration().startTokens().add(token);
|
|
||||||
context.configuration().allowedContexts().add(newContext);
|
|
||||||
saveContainerState();
|
|
||||||
//loadKeyForToken(Arrays.asList(token));
|
|
||||||
context.events().fire(token, ContextEvents.ADD_TOKEN_TO_APPLICATION);
|
|
||||||
context.events().fire(token, ProfileEvents.addToContext);
|
|
||||||
log.trace("token added and event fired");
|
|
||||||
} else log.warn("trying to add an invalid token");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Observes(value=ContextEvents.REMOVE_TOKEN_FROM_CONTAINER,kind=Kind.critical)
|
|
||||||
void removeToken(String token) {
|
|
||||||
log.trace("removing token {} from container", token);
|
|
||||||
AuthorizationEntry entry;
|
|
||||||
try {
|
|
||||||
entry = authProvider.get(token);
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.error("error resolving token to remove");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (context.configuration().startTokens().contains(token)) {
|
|
||||||
context.configuration().startTokens().remove(token);
|
|
||||||
context.configuration().allowedContexts().remove(entry.getContext());
|
|
||||||
saveContainerState();
|
|
||||||
context.events().fire(token, ContextEvents.REMOVE_TOKEN_FROM_APPLICATION);
|
|
||||||
context.events().fire(token, ProfileEvents.removeFromContext);
|
|
||||||
log.trace("token removed and event fired");
|
|
||||||
} else log.warn("cannot remove token, it is not present in the container");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stops container management on remote request.
|
* Stops container management on remote request.
|
||||||
*
|
*
|
||||||
|
@ -217,18 +130,20 @@ public class ContainerManager {
|
||||||
stop(false);
|
stop(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stops container management on remote request or container shutdown.
|
* Stops container management on remote request or container shutdown.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public void stop(boolean shutdown) {
|
public void stop(boolean shutdown) {
|
||||||
|
|
||||||
//two cases: stop-on-shutdown and stop-on-request, some listeners will be selective about this,
|
// two cases: stop-on-shutdown and stop-on-request, some listeners will be
|
||||||
|
// selective about this,
|
||||||
|
|
||||||
// shutdown is triggered by probe app, which is notified among other apps
|
// shutdown is triggered by probe app, which is notified among other apps
|
||||||
//if other app have been already notified, the container may already be part-active.
|
// if other app have been already notified, the container may already be
|
||||||
//apps still to notify will listen only on stop, hence won't react to this but will go down when their turn arrives.
|
// part-active.
|
||||||
|
// apps still to notify will listen only on stop, hence won't react to this but
|
||||||
|
// will go down when their turn arrives.
|
||||||
|
|
||||||
if (context == null)
|
if (context == null)
|
||||||
return;
|
return;
|
||||||
|
@ -246,16 +161,13 @@ public class ContainerManager {
|
||||||
context.events().stop();
|
context.events().stop();
|
||||||
Utils.scheduledServicePool.shutdownNow();
|
Utils.scheduledServicePool.shutdownNow();
|
||||||
|
|
||||||
}
|
} catch (RuntimeException e) {
|
||||||
catch (RuntimeException e) {
|
|
||||||
|
|
||||||
log.warn("cannot stop container management (see cause)", e);
|
log.warn("cannot stop container management (see cause)", e);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// helpers
|
// helpers
|
||||||
|
|
||||||
private void startHandlers(List<ContainerHandler> handlers) {
|
private void startHandlers(List<ContainerHandler> handlers) {
|
||||||
|
@ -273,7 +185,6 @@ public class ContainerManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void stopHandlers() {
|
private void stopHandlers() {
|
||||||
|
|
||||||
if (pipeline == null)
|
if (pipeline == null)
|
||||||
|
@ -287,45 +198,31 @@ public class ContainerManager {
|
||||||
|
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
private void loadKeyForToken(List<String> tokens) {
|
* private void loadKeyForToken(List<String> tokens) { String initialToken =
|
||||||
String initialToken = SecurityTokenProvider.instance.get();
|
* SecurityTokenProvider.instance.get();
|
||||||
|
*
|
||||||
//TODO: change this
|
* //TODO: change this String filePath = "/tmp/keys"; File PathDirs = new
|
||||||
String filePath = "/tmp/keys";
|
* File(filePath+"/"); PathDirs.mkdirs(); try{ for (String token : tokens) {
|
||||||
File PathDirs = new File(filePath+"/");
|
* try{ SecurityTokenProvider.instance.set(token); File key =
|
||||||
PathDirs.mkdirs();
|
* authProvider.getSymmKey(filePath);
|
||||||
try{
|
* log.trace("loading key {} file name ",key.getAbsolutePath());
|
||||||
for (String token : tokens) {
|
* log.trace("loaded key {} file name ",key.getAbsolutePath()); }catch(Exception
|
||||||
try{
|
* e){ log.warn("error loading key for token {}", token, e); } }
|
||||||
SecurityTokenProvider.instance.set(token);
|
* loadFileIntoClasspath(PathDirs); }finally{
|
||||||
File key = authProvider.getSymmKey(filePath);
|
* SecurityTokenProvider.instance.set(initialToken); } }
|
||||||
log.trace("loading key {} file name ",key.getAbsolutePath());
|
*
|
||||||
log.trace("loaded key {} file name ",key.getAbsolutePath());
|
*
|
||||||
}catch(Exception e){
|
* private void loadFileIntoClasspath(File file){ try { URL url =
|
||||||
log.warn("error loading key for token {}", token, e);
|
* file.toURI().toURL();
|
||||||
}
|
*
|
||||||
}
|
* ClassLoader currentClassloader =
|
||||||
loadFileIntoClasspath(PathDirs);
|
* Thread.currentThread().getContextClassLoader().getParent()==null?
|
||||||
}finally{
|
* Thread.currentThread().getContextClassLoader() :
|
||||||
SecurityTokenProvider.instance.set(initialToken);
|
* Thread.currentThread().getContextClassLoader().getParent();
|
||||||
}
|
*
|
||||||
}
|
* URLClassLoader classLoader = (URLClassLoader)currentClassloader; Method
|
||||||
|
* method = URLClassLoader.class.getDeclaredMethod("addURL", URL.class);
|
||||||
|
* method.setAccessible(true); method.invoke(classLoader, url); } catch
|
||||||
private void loadFileIntoClasspath(File file){
|
* (Exception ex) { log.error("error loading file into classpath",ex); } }
|
||||||
try {
|
|
||||||
URL url = file.toURI().toURL();
|
|
||||||
|
|
||||||
ClassLoader currentClassloader = Thread.currentThread().getContextClassLoader().getParent()==null?
|
|
||||||
Thread.currentThread().getContextClassLoader() : Thread.currentThread().getContextClassLoader().getParent();
|
|
||||||
|
|
||||||
URLClassLoader classLoader = (URLClassLoader)currentClassloader;
|
|
||||||
Method method = URLClassLoader.class.getDeclaredMethod("addURL", URL.class);
|
|
||||||
method.setAccessible(true);
|
|
||||||
method.invoke(classLoader, url);
|
|
||||||
} catch (Exception ex) {
|
|
||||||
log.error("error loading file into classpath",ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,12 +2,9 @@ package org.gcube.smartgears.managers;
|
||||||
|
|
||||||
public class ContextEvents {
|
public class ContextEvents {
|
||||||
|
|
||||||
public static final String ADD_TOKEN_TO_CONTAINER ="AddTokenToContainer";
|
public static final String ADD_CONTEXT_TO_CONTAINER ="AddContextToContainer";
|
||||||
|
|
||||||
public static final String ADD_TOKEN_TO_APPLICATION ="AddTokenToApplication";
|
public static final String REMOVE_CONTEXT_FROM_CONTAINER ="RemoveContextFromContainer";
|
||||||
|
|
||||||
public static final String REMOVE_TOKEN_FROM_CONTAINER ="RemoveTokenFromContainer";
|
|
||||||
|
|
||||||
public static final String REMOVE_TOKEN_FROM_APPLICATION ="RemoveTokenFromApplication";
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,19 +8,21 @@ import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import javax.servlet.Filter;
|
import jakarta.servlet.Filter;
|
||||||
import javax.servlet.FilterChain;
|
import jakarta.servlet.FilterChain;
|
||||||
import javax.servlet.FilterConfig;
|
import jakarta.servlet.FilterConfig;
|
||||||
import javax.servlet.ServletException;
|
import jakarta.servlet.ServletException;
|
||||||
import javax.servlet.ServletRequest;
|
import jakarta.servlet.ServletRequest;
|
||||||
import javax.servlet.ServletResponse;
|
import jakarta.servlet.ServletResponse;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
import org.gcube.common.authorization.library.exception.AuthorizationException;
|
import org.gcube.common.authorization.library.exception.AuthorizationException;
|
||||||
import org.gcube.smartgears.configuration.application.Exclude;
|
import org.gcube.smartgears.Constants;
|
||||||
import org.gcube.smartgears.configuration.application.Include;
|
import org.gcube.smartgears.configuration.application.GCubeExclude;
|
||||||
|
import org.gcube.smartgears.configuration.application.GCubeInclude;
|
||||||
import org.gcube.smartgears.context.application.ApplicationContext;
|
import org.gcube.smartgears.context.application.ApplicationContext;
|
||||||
import org.gcube.smartgears.context.application.DefaultApplicationContext;
|
import org.gcube.smartgears.context.application.DefaultApplicationContext;
|
||||||
import org.gcube.smartgears.handlers.application.ApplicationPipeline;
|
import org.gcube.smartgears.handlers.application.ApplicationPipeline;
|
||||||
|
@ -123,40 +125,49 @@ public class RequestManager implements Filter {
|
||||||
|
|
||||||
String query = request.getQueryString();
|
String query = request.getQueryString();
|
||||||
|
|
||||||
log.debug("servletPath is {} and pathInfo is {}",request.getServletPath(), request.getPathInfo());
|
log.trace("servletPath is {} and pathInfo is {}",request.getServletPath(), request.getPathInfo());
|
||||||
|
|
||||||
if ("wsdl".equals(query) || "wsdl=1".equals(query))
|
|
||||||
|
//excludes also mandatory filter for extensions
|
||||||
|
if ("wsdl".equals(query) || "wsdl=1".equals(query) ||
|
||||||
|
request.getServletPath().equals(Constants.root_mapping))
|
||||||
return Collections.emptyList();
|
return Collections.emptyList();
|
||||||
|
|
||||||
|
|
||||||
String path = request.getServletPath()==null?"":request.getServletPath();
|
String path = request.getServletPath()==null?"":request.getServletPath();
|
||||||
|
|
||||||
path += request.getPathInfo() ==null?"":request.getPathInfo();
|
path += request.getPathInfo() ==null?"":request.getPathInfo();
|
||||||
|
|
||||||
|
log.trace("check which handler should be excluded {}", path);
|
||||||
log.debug("check wich handler should be excluded {}", path);
|
|
||||||
|
|
||||||
if (!context.configuration().excludes().isEmpty()) {
|
if (!context.configuration().excludes().isEmpty()) {
|
||||||
for (Exclude exclude : context.configuration().excludes()){
|
log.debug("excludes are not empty");
|
||||||
|
for (GCubeExclude exclude : context.configuration().excludes()){
|
||||||
String excludePath= exclude.getPath();
|
String excludePath= exclude.getPath();
|
||||||
log.trace("exclude is {}",exclude);
|
log.debug("exclude is {}",exclude);
|
||||||
if (
|
if ((WILDCARD).equals(excludePath) ||
|
||||||
(WILDCARD).equals(excludePath) ||
|
|
||||||
(excludePath.endsWith(WILDCARD) && path!=null && path.startsWith(excludePath.substring(0,excludePath.length()-2))) ||
|
(excludePath.endsWith(WILDCARD) && path!=null && path.startsWith(excludePath.substring(0,excludePath.length()-2))) ||
|
||||||
excludePath.equals(path) || (path.endsWith("/") && excludePath.equals(path.substring(0, path.length()-1)))
|
excludePath.equals(path) || (path.endsWith("/") && excludePath.equals(path.substring(0, path.length()-1)))
|
||||||
){
|
){
|
||||||
//ALL handler are filtered
|
//ALL handler are filtered except for unfilterable
|
||||||
if (exclude.getHandlers().isEmpty()) return Collections.emptyList();
|
if (exclude.getHandlers().isEmpty()) {
|
||||||
|
List<RequestHandler> unfilterables = handlersToFilter.stream()
|
||||||
|
.filter(RequestHandler::isUnfiltrable).collect(Collectors.toList());
|
||||||
|
log.trace("exclude handler is empty so unfilterable handlers are {}",unfilterables);
|
||||||
|
return handlersToFilter.stream()
|
||||||
|
.filter(RequestHandler::isUnfiltrable).collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
List<RequestHandler> filteredHandlers = new ArrayList<>();
|
List<RequestHandler> filteredHandlers = new ArrayList<>();
|
||||||
for (RequestHandler rh : handlersToFilter){
|
for (RequestHandler rh : handlersToFilter)
|
||||||
if (!exclude.getHandlers().contains(rh.getName()))
|
if (rh.isUnfiltrable() || !exclude.getHandlers().contains(rh.getName()))
|
||||||
filteredHandlers.add(rh);
|
filteredHandlers.add(rh);
|
||||||
}
|
|
||||||
return filteredHandlers;
|
return filteredHandlers;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (!context.configuration().includes().isEmpty()) {
|
} else if (!context.configuration().includes().isEmpty()) {
|
||||||
for (Include include : context.configuration().includes()){
|
for (GCubeInclude include : context.configuration().includes()){
|
||||||
String includePath= include.getPath();
|
String includePath= include.getPath();
|
||||||
log.trace("include is {}",include);
|
log.trace("include is {}",include);
|
||||||
if (
|
if (
|
||||||
|
@ -168,16 +179,16 @@ public class RequestManager implements Filter {
|
||||||
if (include.getHandlers().isEmpty()) return handlersToFilter;
|
if (include.getHandlers().isEmpty()) return handlersToFilter;
|
||||||
|
|
||||||
List<RequestHandler> filteredHandlers = new ArrayList<>();
|
List<RequestHandler> filteredHandlers = new ArrayList<>();
|
||||||
for (RequestHandler rh : handlersToFilter){
|
for (RequestHandler rh : handlersToFilter)
|
||||||
if (include.getHandlers().contains(rh.getName()))
|
if (rh.isUnfiltrable() || include.getHandlers().contains(rh.getName()))
|
||||||
filteredHandlers.add(rh);
|
filteredHandlers.add(rh);
|
||||||
}
|
|
||||||
return filteredHandlers;
|
return filteredHandlers;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return new ArrayList<>();
|
return new ArrayList<>();
|
||||||
}
|
}
|
||||||
|
log.trace("returning original handlers");
|
||||||
return handlersToFilter;
|
return handlersToFilter;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -213,37 +224,6 @@ public class RequestManager implements Filter {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// helpers
|
|
||||||
/*
|
|
||||||
private boolean shouldExcludeRequest(HttpServletRequest request) {
|
|
||||||
|
|
||||||
String query = request.getQueryString();
|
|
||||||
|
|
||||||
log.debug("servletPath is {} and pathInfo is {}",request.getServletPath(), request.getPathInfo());
|
|
||||||
|
|
||||||
if ("wsdl".equals(query) || "wsdl=1".equals(query))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
String path = request.getServletPath()==null?"":request.getServletPath();
|
|
||||||
|
|
||||||
path += request.getPathInfo() ==null?"":request.getPathInfo();
|
|
||||||
|
|
||||||
|
|
||||||
log.debug("check if should exclude call with path {}", path);
|
|
||||||
|
|
||||||
for (Exclude exclude : context.configuration().excludes()){
|
|
||||||
if (!exclude.getHandlers().isEmpty()) continue;
|
|
||||||
String excludePath= exclude.getPath();
|
|
||||||
log.trace("exclude is {}",exclude);
|
|
||||||
if (
|
|
||||||
(EXCLUDE_ALL).equals(exclude) ||
|
|
||||||
(excludePath.endsWith(EXCLUDE_ALL) && path!=null && path.startsWith(excludePath.substring(0,excludePath.length()-2))) ||
|
|
||||||
excludePath.equals(path) || (path.endsWith("/") && excludePath.equals(path.substring(0, path.length()-1)))
|
|
||||||
)
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}*/
|
|
||||||
|
|
||||||
private void handleError(HttpServletRequest request, HttpServletResponse response,Throwable t) throws IOException {
|
private void handleError(HttpServletRequest request, HttpServletResponse response,Throwable t) throws IOException {
|
||||||
|
|
||||||
|
|
|
@ -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,7 +1,7 @@
|
||||||
package org.gcube.smartgears.probe;
|
package org.gcube.smartgears.probe;
|
||||||
|
|
||||||
import javax.servlet.ServletContextListener;
|
import jakarta.servlet.ServletContextListener;
|
||||||
import javax.servlet.annotation.WebListener;
|
import jakarta.servlet.annotation.WebListener;
|
||||||
|
|
||||||
import org.gcube.smartgears.managers.ContainerManager;
|
import org.gcube.smartgears.managers.ContainerManager;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
|
@ -12,12 +12,12 @@ public class ContainerListener implements ServletContextListener {
|
||||||
|
|
||||||
public static Logger log = LoggerFactory.getLogger(ContainerListener.class);
|
public static Logger log = LoggerFactory.getLogger(ContainerListener.class);
|
||||||
|
|
||||||
public void contextDestroyed(javax.servlet.ServletContextEvent sce) {
|
public void contextDestroyed(jakarta.servlet.ServletContextEvent sce) {
|
||||||
log.trace("shutting down container from probe");
|
log.trace("shutting down container from probe");
|
||||||
ContainerManager.instance.stop(true);
|
ContainerManager.instance.stop(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
public void contextInitialized(javax.servlet.ServletContextEvent sce) {
|
public void contextInitialized(jakarta.servlet.ServletContextEvent sce) {
|
||||||
log.trace("starting up probe...");
|
log.trace("starting up probe...");
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,66 +1,52 @@
|
||||||
package org.gcube.smartgears.provider;
|
package org.gcube.smartgears.provider;
|
||||||
|
|
||||||
import static org.gcube.common.authorization.client.Constants.authorizationService;
|
|
||||||
import static org.gcube.smartgears.Constants.configuration_file_path;
|
import static org.gcube.smartgears.Constants.configuration_file_path;
|
||||||
import static org.gcube.smartgears.Constants.container_configuraton_file_path;
|
import static org.gcube.smartgears.Constants.container_configuraton_file_path;
|
||||||
import static org.gcube.smartgears.Constants.container_handlers_file_name;
|
|
||||||
import static org.gcube.smartgears.Constants.application_handlers_file_name;
|
|
||||||
import static org.gcube.smartgears.Constants.container_handlers_file_path;
|
|
||||||
import static org.gcube.smartgears.Constants.container_profile_file_path;
|
|
||||||
import static org.gcube.smartgears.Constants.default_extensions_file_path;
|
|
||||||
import static org.gcube.smartgears.Constants.default_handlers_file_path;
|
|
||||||
import static org.gcube.smartgears.Constants.extensions_file_path;
|
|
||||||
import static org.gcube.smartgears.Constants.ghn_home_env;
|
import static org.gcube.smartgears.Constants.ghn_home_env;
|
||||||
import static org.gcube.smartgears.Constants.ghn_home_property;
|
import static org.gcube.smartgears.Constants.ghn_home_property;
|
||||||
import static org.gcube.smartgears.Constants.handlers_file_path;
|
|
||||||
import static org.gcube.smartgears.Constants.library_configuration_file_path;
|
|
||||||
import static org.gcube.smartgears.Constants.profile_file_path;
|
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.ObjectInputStream;
|
import java.util.ArrayList;
|
||||||
import java.net.URL;
|
|
||||||
import java.net.URLClassLoader;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.UUID;
|
import java.util.Set;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import jakarta.servlet.ServletContext;
|
||||||
|
|
||||||
import javax.servlet.ServletContext;
|
|
||||||
import org.gcube.common.authorization.client.proxy.AuthorizationProxy;
|
|
||||||
import org.gcube.common.events.Hub;
|
import org.gcube.common.events.Hub;
|
||||||
import org.gcube.common.events.impl.DefaultHub;
|
import org.gcube.common.events.impl.DefaultHub;
|
||||||
import org.gcube.common.scan.ClasspathScanner;
|
import org.gcube.common.security.credentials.Credentials;
|
||||||
import org.gcube.common.scan.ClasspathScannerFactory;
|
import org.gcube.common.security.factories.AuthorizationProvider;
|
||||||
import org.gcube.common.scan.matchers.NameMatcher;
|
import org.gcube.common.security.factories.AuthorizationProviderFactory;
|
||||||
import org.gcube.common.scan.resources.ClasspathResource;
|
import org.gcube.smartgears.configuration.SmartgearsConfiguration;
|
||||||
import org.gcube.informationsystem.publisher.RegistryPublisherFactory;
|
|
||||||
import org.gcube.informationsystem.publisher.ScopedPublisher;
|
|
||||||
import org.gcube.smartgears.configuration.Mode;
|
|
||||||
import org.gcube.smartgears.configuration.application.ApplicationConfiguration;
|
import org.gcube.smartgears.configuration.application.ApplicationConfiguration;
|
||||||
import org.gcube.smartgears.configuration.application.ApplicationConfigurationBinder;
|
import org.gcube.smartgears.configuration.application.ApplicationConfigurationBinder;
|
||||||
import org.gcube.smartgears.configuration.application.ApplicationExtensions;
|
|
||||||
import org.gcube.smartgears.configuration.application.ApplicationHandlers;
|
import org.gcube.smartgears.configuration.application.ApplicationHandlers;
|
||||||
import org.gcube.smartgears.configuration.application.BridgedApplicationConfiguration;
|
|
||||||
import org.gcube.smartgears.configuration.container.ContainerConfiguration;
|
import org.gcube.smartgears.configuration.container.ContainerConfiguration;
|
||||||
import org.gcube.smartgears.configuration.container.ContainerConfigurationBinder;
|
import org.gcube.smartgears.configuration.container.ContainerConfigurationBinder;
|
||||||
import org.gcube.smartgears.configuration.container.ContainerHandlers;
|
|
||||||
import org.gcube.smartgears.configuration.library.SmartGearsConfiguration;
|
|
||||||
import org.gcube.smartgears.configuration.library.SmartGearsConfigurationBinder;
|
|
||||||
import org.gcube.smartgears.context.Properties;
|
import org.gcube.smartgears.context.Properties;
|
||||||
import org.gcube.smartgears.context.application.ApplicationContext;
|
import org.gcube.smartgears.context.application.ApplicationContext;
|
||||||
import org.gcube.smartgears.context.application.DefaultApplicationContext;
|
import org.gcube.smartgears.context.application.DefaultApplicationContext;
|
||||||
import org.gcube.smartgears.context.container.ContainerContext;
|
import org.gcube.smartgears.context.container.ContainerContext;
|
||||||
import org.gcube.smartgears.context.container.DefaultContainerContext;
|
import org.gcube.smartgears.context.container.DefaultContainerContext;
|
||||||
|
import org.gcube.smartgears.extensions.ApplicationExtension;
|
||||||
|
import org.gcube.smartgears.extensions.resource.RemoteResource;
|
||||||
|
import org.gcube.smartgears.handlers.container.ContainerHandler;
|
||||||
import org.gcube.smartgears.lifecycle.application.ApplicationLifecycle;
|
import org.gcube.smartgears.lifecycle.application.ApplicationLifecycle;
|
||||||
import org.gcube.smartgears.lifecycle.container.ContainerLifecycle;
|
import org.gcube.smartgears.lifecycle.container.ContainerLifecycle;
|
||||||
import org.gcube.smartgears.persistence.DefaultPersistence;
|
import org.gcube.smartgears.publishing.Publisher;
|
||||||
|
import org.gcube.smartgears.publishing.SmartgearsProfilePublisher;
|
||||||
import org.gcube.smartgears.utils.Utils;
|
import org.gcube.smartgears.utils.Utils;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import io.github.classgraph.ClassGraph;
|
||||||
|
import io.github.classgraph.ClassInfo;
|
||||||
|
import io.github.classgraph.ClassInfoList;
|
||||||
|
import io.github.classgraph.ScanResult;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Default implementation of the {@link Provider} interface.
|
* Default implementation of the {@link Provider} interface.
|
||||||
*
|
*
|
||||||
|
@ -74,105 +60,54 @@ public class DefaultProvider implements Provider {
|
||||||
private ContainerContext containerContext;
|
private ContainerContext containerContext;
|
||||||
// TODO: do the same with applicationContext (with a map)
|
// TODO: do the same with applicationContext (with a map)
|
||||||
|
|
||||||
protected DefaultProvider(){};
|
private File configFile = null;
|
||||||
|
|
||||||
|
protected DefaultProvider(File configFile) {
|
||||||
|
this.configFile = configFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Publisher> publishers;
|
||||||
|
|
||||||
|
protected DefaultProvider() {
|
||||||
|
};
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
@Override
|
@Override
|
||||||
public ContainerContext containerContext() {
|
public ContainerContext containerContext() {
|
||||||
|
|
||||||
if (containerContext == null) {
|
if (containerContext == null) {
|
||||||
ContainerConfiguration configuration = containerConfiguration();
|
ContainerConfiguration configuration = containerConfiguration();
|
||||||
|
|
||||||
if (configuration.persistence()==null) {
|
|
||||||
String location = Utils.home()+"/state";
|
|
||||||
File dir = new File(location);
|
|
||||||
if (!dir.exists())
|
|
||||||
dir.mkdirs();
|
|
||||||
configuration.persistence(new DefaultPersistence(location));
|
|
||||||
|
|
||||||
log.trace("setting persistence location for container @ {}",dir.getAbsolutePath());
|
|
||||||
}
|
|
||||||
|
|
||||||
Hub hub = new DefaultHub();
|
Hub hub = new DefaultHub();
|
||||||
|
|
||||||
ContainerLifecycle lifecycle = new ContainerLifecycle(hub);
|
ContainerLifecycle lifecycle = new ContainerLifecycle(hub);
|
||||||
|
|
||||||
File file = configuration.persistence().file(container_profile_file_path);
|
AuthorizationProviderFactory<?> authfactory = configuration.authorizationConfiguration()
|
||||||
|
.getAuthProviderFactory();
|
||||||
|
Credentials credentials = configuration.authorizationConfiguration().getCredentials();
|
||||||
|
|
||||||
String id = null;
|
AuthorizationProvider authProvider = authfactory.connect(credentials);
|
||||||
List<String> tokens = null;
|
|
||||||
if (file.exists()){
|
|
||||||
log.info("loading persisted state for container");
|
|
||||||
try(ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file))){
|
|
||||||
id = (String)ois.readObject();
|
|
||||||
tokens = (List<String>) ois.readObject();
|
|
||||||
}catch(Exception e){
|
|
||||||
log.error("error loading persisted state, creating new uuid",e);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
containerContext = new DefaultContainerContext(configuration, hub, lifecycle, authProvider,
|
||||||
if (id==null){
|
new Properties());
|
||||||
id = UUID.randomUUID().toString();
|
|
||||||
log.info("container id created is {}",id);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tokens!=null)
|
|
||||||
configuration.startTokens(tokens);
|
|
||||||
|
|
||||||
containerContext = new DefaultContainerContext(id, configuration, hub, lifecycle, new Properties());
|
|
||||||
}
|
}
|
||||||
return containerContext;
|
return containerContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ContainerHandlers containerHandlers() {
|
public List<ContainerHandler> containerHandlers() {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
InputStream config = getClass().getResourceAsStream(container_handlers_file_path);
|
|
||||||
|
|
||||||
if (config == null)
|
|
||||||
throw new IllegalStateException("invalid distribution: cannot find " + container_handlers_file_path);
|
|
||||||
|
|
||||||
ContainerConfigurationBinder binder = new ContainerConfigurationBinder();
|
ContainerConfigurationBinder binder = new ContainerConfigurationBinder();
|
||||||
ContainerHandlers defaultHandlers = binder.bindHandlers(config);
|
|
||||||
|
|
||||||
ClassLoader currentClassLoader = Thread.currentThread().getContextClassLoader();
|
ClassLoader currentClassLoader = Thread.currentThread().getContextClassLoader();
|
||||||
if (currentClassLoader.getParent()!=null && !currentClassLoader.getParent().equals(ClassLoader.getSystemClassLoader())){
|
if (currentClassLoader.getParent() != null
|
||||||
|
&& !currentClassLoader.getParent().equals(ClassLoader.getSystemClassLoader())) {
|
||||||
log.trace("probably i'm in a webapp classloader");
|
log.trace("probably i'm in a webapp classloader");
|
||||||
currentClassLoader = currentClassLoader.getParent();
|
currentClassLoader = currentClassLoader.getParent();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
List<ContainerHandler> defaultHandlers = binder.bindHandlers(currentClassLoader);
|
||||||
try{
|
|
||||||
if (currentClassLoader instanceof URLClassLoader){
|
|
||||||
URL[] urls = ((URLClassLoader) currentClassLoader).getURLs() ;
|
|
||||||
|
|
||||||
if (urls!=null && urls.length>0){
|
|
||||||
ClasspathScanner scanner = ClasspathScannerFactory.scanner(new HashSet<URL>(Arrays.asList(urls)));
|
|
||||||
Collection<ClasspathResource> resources = scanner.scan(new NameMatcher(container_handlers_file_name));
|
|
||||||
|
|
||||||
for (URL url: urls)
|
|
||||||
log.trace("URL: "+ url.toString());
|
|
||||||
|
|
||||||
if (resources==null || resources.isEmpty())
|
|
||||||
log.info("no custom container handlers found in the classpath");
|
|
||||||
|
|
||||||
for (ClasspathResource res : resources){
|
|
||||||
try{
|
|
||||||
ContainerHandlers customHandlers= binder.bindHandlers(res.stream());
|
|
||||||
defaultHandlers.mergeWith(customHandlers);
|
|
||||||
log.trace("container hadlers found in {}",res.name());
|
|
||||||
}catch(Exception e){
|
|
||||||
log.warn("error loading not default container handlers {}",res.name(),e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else log.info("this classloader is not instance of {} : ",URLClassLoader.class.getName(), currentClassLoader.getClass().getName());
|
|
||||||
}catch(Exception e){
|
|
||||||
log.warn("cannot load custom handlers for container from the root classloader",e);
|
|
||||||
}
|
|
||||||
|
|
||||||
return defaultHandlers;
|
return defaultHandlers;
|
||||||
|
|
||||||
|
@ -186,63 +121,20 @@ public class DefaultProvider implements Provider {
|
||||||
@Override
|
@Override
|
||||||
public ApplicationContext contextFor(ContainerContext context, ServletContext application) {
|
public ApplicationContext contextFor(ContainerContext context, ServletContext application) {
|
||||||
|
|
||||||
ApplicationConfiguration configuration = null;
|
|
||||||
ApplicationConfiguration embedded = configurationFor(application);
|
ApplicationConfiguration embedded = configurationFor(application);
|
||||||
ApplicationConfiguration external = context.configuration().app(application.getContextPath());
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// shouldn't happen: management shouldn't have started at all
|
// shouldn't happen: management shouldn't have started at all
|
||||||
if (embedded==null && external==null)
|
if (embedded == null)
|
||||||
throw new AssertionError("application @ " + application.getContextPath() + " is not distributed with "
|
throw new AssertionError("application @ " + application.getContextPath() + " is not distributed with "
|
||||||
+ configuration_file_path+" and there is no external configuration for it in "+container_configuraton_file_path);
|
+ configuration_file_path + " and there is no external configuration for it in "
|
||||||
|
+ container_configuraton_file_path);
|
||||||
|
|
||||||
//no embedded configuration
|
|
||||||
if (embedded == null) {
|
|
||||||
|
|
||||||
configuration = external ;
|
|
||||||
|
|
||||||
log.info("loaded configuration for application "+configuration.name()+" from "+container_configuraton_file_path);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
|
|
||||||
configuration = embedded;
|
|
||||||
|
|
||||||
if (external == null)
|
|
||||||
|
|
||||||
log.info("loaded configuration for application "+configuration.name()+" from "+configuration_file_path);
|
|
||||||
|
|
||||||
else {
|
|
||||||
|
|
||||||
configuration.merge(external);
|
|
||||||
|
|
||||||
log.info("loaded configuration for application "+configuration.name()+" from "+configuration_file_path+" and "+container_configuraton_file_path);
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO we can check scopes here instead of in BridgedApplicationConfiguration constructor
|
|
||||||
ApplicationConfiguration bridgedConfiguration = new BridgedApplicationConfiguration(context.configuration(),
|
|
||||||
configuration);
|
|
||||||
|
|
||||||
Hub hub = new DefaultHub();
|
Hub hub = new DefaultHub();
|
||||||
|
|
||||||
ApplicationLifecycle lifecycle = new ApplicationLifecycle(hub, configuration.name());
|
ApplicationLifecycle lifecycle = new ApplicationLifecycle(hub, embedded.name());
|
||||||
|
|
||||||
File file = bridgedConfiguration.persistence().file(profile_file_path);
|
return new DefaultApplicationContext(context, application, embedded, hub, lifecycle,
|
||||||
String id= null;
|
|
||||||
if (file.exists()){
|
|
||||||
log.info("loading persisted state for application {}", application.getContextPath());
|
|
||||||
try(ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file))){
|
|
||||||
id = (String)ois.readObject();
|
|
||||||
}catch(Exception e){
|
|
||||||
log.error("error loading persisted state, creating new uuid",e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (id==null)
|
|
||||||
id = UUID.randomUUID().toString();
|
|
||||||
|
|
||||||
return new DefaultApplicationContext(id, context, application, bridgedConfiguration, hub, lifecycle,
|
|
||||||
new Properties());
|
new Properties());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -251,128 +143,34 @@ public class DefaultProvider implements Provider {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
// it's in a library, using
|
|
||||||
InputStream defaultHandlersStream = getClass().getResourceAsStream(default_handlers_file_path);
|
|
||||||
|
|
||||||
if (defaultHandlersStream == null)
|
|
||||||
throw new IllegalStateException("invalid distribution: cannot find " + default_handlers_file_path);
|
|
||||||
|
|
||||||
ApplicationConfigurationBinder binder = new ApplicationConfigurationBinder();
|
ApplicationConfigurationBinder binder = new ApplicationConfigurationBinder();
|
||||||
|
|
||||||
ApplicationHandlers defaultHandlers = binder.bindHandlers(defaultHandlersStream);
|
// searching for smartegars related application handlers in the common
|
||||||
|
// classloader
|
||||||
//searching for smartegars related application handlers in the common classloader
|
|
||||||
ClassLoader currentClassLoader = Thread.currentThread().getContextClassLoader();
|
ClassLoader currentClassLoader = Thread.currentThread().getContextClassLoader();
|
||||||
if (currentClassLoader.getParent()!=null && !currentClassLoader.getParent().equals(ClassLoader.getSystemClassLoader())){
|
if (currentClassLoader.getParent() != null
|
||||||
|
&& !currentClassLoader.getParent().equals(ClassLoader.getSystemClassLoader())) {
|
||||||
log.trace("probably i'm in a webapp classloader");
|
log.trace("probably i'm in a webapp classloader");
|
||||||
currentClassLoader = currentClassLoader.getParent();
|
currentClassLoader = currentClassLoader.getParent();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ApplicationHandlers defaultHandlers = binder.bindHandlers(currentClassLoader);
|
||||||
try{
|
|
||||||
if (currentClassLoader instanceof URLClassLoader){
|
|
||||||
URL[] urls = ((URLClassLoader) currentClassLoader).getURLs() ;
|
|
||||||
|
|
||||||
if (urls!=null && urls.length>0){
|
|
||||||
ClasspathScanner scanner = ClasspathScannerFactory.scanner(new HashSet<URL>(Arrays.asList(urls)));
|
|
||||||
Collection<ClasspathResource> resources = scanner.scan(new NameMatcher(application_handlers_file_name));
|
|
||||||
if (resources==null || resources.isEmpty())
|
|
||||||
log.info("no custom smartgears related application handlers found in the classpath");
|
|
||||||
|
|
||||||
for (ClasspathResource res : resources){
|
|
||||||
try{
|
|
||||||
ApplicationHandlers customHandlers= binder.bindHandlers(res.stream());
|
|
||||||
defaultHandlers.mergeWith(customHandlers);
|
|
||||||
log.trace("application hadlers found in {}",res.name());
|
|
||||||
}catch(Exception e){
|
|
||||||
log.warn("error loading smartgears related application handlers {}",res.name(),e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}catch(Exception e){
|
|
||||||
log.warn("cannot load smartgears related handlers for application from the root classloader",e);
|
|
||||||
}
|
|
||||||
|
|
||||||
InputStream appSpecificHandlersStream = context.application().getResourceAsStream(handlers_file_path);
|
|
||||||
|
|
||||||
if (appSpecificHandlersStream !=null ){
|
|
||||||
defaultHandlers.mergeWith(binder.bindHandlers(appSpecificHandlersStream));
|
|
||||||
log.trace("{} uses default lifecycle with app spceific handler as it includes {}", context.name(), handlers_file_path);
|
|
||||||
} else
|
|
||||||
log.trace("{} uses the default lifecycle as it does not include {}", context.name(), handlers_file_path);
|
|
||||||
|
|
||||||
return defaultHandlers;
|
return defaultHandlers;
|
||||||
|
|
||||||
|
|
||||||
} catch (RuntimeException e) {
|
} catch (RuntimeException e) {
|
||||||
|
|
||||||
throw new RuntimeException("cannot install handlers for application @ " + context.name()+" (see cause) ", e);
|
throw new RuntimeException("cannot install handlers for application @ " + context.name() + " (see cause) ",
|
||||||
|
e);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<ApplicationExtension> extensionsFor(ApplicationContext context){
|
||||||
@Override
|
return List.of(new RemoteResource());
|
||||||
public ApplicationExtensions extensionsFor(ApplicationContext context) {
|
|
||||||
|
|
||||||
try {
|
|
||||||
|
|
||||||
InputStream config = context.application().getResourceAsStream(extensions_file_path);
|
|
||||||
|
|
||||||
if (config == null) {
|
|
||||||
|
|
||||||
log.trace("{} uses default extensions as it does not include {}", context.name(), extensions_file_path);
|
|
||||||
|
|
||||||
// it's in a library, using
|
|
||||||
config = getClass().getResourceAsStream(default_extensions_file_path);
|
|
||||||
|
|
||||||
if (config == null)
|
|
||||||
throw new IllegalStateException("invalid distribution: cannot find " + default_extensions_file_path);
|
|
||||||
|
|
||||||
} else
|
|
||||||
log.info("{} uses custom extensions @ {}", context.name(), extensions_file_path);
|
|
||||||
|
|
||||||
ApplicationConfigurationBinder binder = new ApplicationConfigurationBinder();
|
|
||||||
|
|
||||||
return binder.bindExtensions(config);
|
|
||||||
|
|
||||||
} catch (RuntimeException e) {
|
|
||||||
|
|
||||||
throw new RuntimeException("cannot install extensions for application @ " + context.name()+" (see cause) ", e);
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public SmartGearsConfiguration smartgearsConfiguration() {
|
|
||||||
|
|
||||||
try {
|
|
||||||
|
|
||||||
InputStream config = getClass().getResourceAsStream(library_configuration_file_path);
|
|
||||||
|
|
||||||
if (config == null)
|
|
||||||
throw new IllegalStateException("invalid distribution: cannot find " + library_configuration_file_path);
|
|
||||||
|
|
||||||
SmartGearsConfigurationBinder binder = new SmartGearsConfigurationBinder();
|
|
||||||
|
|
||||||
SmartGearsConfiguration configuration = binder.bind(config);
|
|
||||||
|
|
||||||
configuration.validate();
|
|
||||||
|
|
||||||
return configuration;
|
|
||||||
|
|
||||||
} catch (RuntimeException e) {
|
|
||||||
|
|
||||||
throw new RuntimeException("cannot read library configuration (see cause) ", e);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// helpers
|
// helpers
|
||||||
|
|
||||||
private ApplicationConfiguration configurationFor(ServletContext application) {
|
private ApplicationConfiguration configurationFor(ServletContext application) {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -384,7 +182,7 @@ public class DefaultProvider implements Provider {
|
||||||
|
|
||||||
ApplicationConfigurationBinder binder = new ApplicationConfigurationBinder();
|
ApplicationConfigurationBinder binder = new ApplicationConfigurationBinder();
|
||||||
|
|
||||||
return binder.bind(config);
|
return binder.load(config);
|
||||||
|
|
||||||
} catch (RuntimeException e) {
|
} catch (RuntimeException e) {
|
||||||
|
|
||||||
|
@ -395,6 +193,8 @@ public class DefaultProvider implements Provider {
|
||||||
|
|
||||||
private ContainerConfiguration containerConfiguration() {
|
private ContainerConfiguration containerConfiguration() {
|
||||||
|
|
||||||
|
if (configFile == null) {
|
||||||
|
|
||||||
String home = Utils.home();
|
String home = Utils.home();
|
||||||
|
|
||||||
if (home == null)
|
if (home == null)
|
||||||
|
@ -404,67 +204,90 @@ public class DefaultProvider implements Provider {
|
||||||
File homeDir = new File(home);
|
File homeDir = new File(home);
|
||||||
|
|
||||||
if (!(homeDir.exists() && homeDir.isDirectory() && homeDir.canRead() && homeDir.canWrite()))
|
if (!(homeDir.exists() && homeDir.isDirectory() && homeDir.canRead() && homeDir.canWrite()))
|
||||||
throw new IllegalStateException("invalid node configuration: home "+home+" does not exist or is not a directory or cannot be accessed in read/write mode");
|
throw new IllegalStateException("invalid node configuration: home " + home
|
||||||
|
+ " does not exist or is not a directory or cannot be accessed in read/write mode");
|
||||||
|
|
||||||
File config = new File(homeDir,container_configuraton_file_path);
|
configFile = new File(homeDir, container_configuraton_file_path);
|
||||||
|
|
||||||
if (!(config.exists() && config.canRead()))
|
log.trace("reading container configuration @ {} ", configFile.getAbsolutePath());
|
||||||
throw new IllegalStateException("invalid node configuration: file "+config.getAbsolutePath()+" does not exist or cannot be accessed");
|
|
||||||
|
|
||||||
|
|
||||||
log.trace("reading container configuration @ {} ", config.getAbsolutePath());
|
|
||||||
|
|
||||||
ContainerConfigurationBinder binder = new ContainerConfigurationBinder();
|
|
||||||
|
|
||||||
FileInputStream stream = null;
|
|
||||||
try {
|
|
||||||
|
|
||||||
stream = new FileInputStream(config);
|
|
||||||
|
|
||||||
}
|
|
||||||
catch(Exception e) {
|
|
||||||
throw new RuntimeException("unexpected exception reading container configuration file see cause)",e);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ContainerConfiguration configuration = binder.bind(stream);
|
if (!(configFile.exists() && configFile.canRead()))
|
||||||
|
throw new IllegalStateException("invalid node configuration: file " + configFile.getAbsolutePath()
|
||||||
|
+ " does not exist or cannot be accessed");
|
||||||
|
|
||||||
try {
|
ContainerConfiguration configuration;
|
||||||
stream.close();
|
try (InputStream stream = new FileInputStream(configFile)) {
|
||||||
}
|
configuration = new ContainerConfigurationBinder().load(stream);
|
||||||
catch(Exception e) {
|
} catch (Exception e) {
|
||||||
log.warn("could not close stream when reading container configuration @ "+config.getAbsolutePath()+" (see cause)",e);
|
throw new IllegalStateException(
|
||||||
|
"invalid node configuration: file " + configFile.getAbsolutePath() + " is invalid", e);
|
||||||
}
|
}
|
||||||
|
|
||||||
return configuration;
|
return configuration;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public synchronized List<Publisher> publishers() {
|
||||||
|
if (this.publishers == null) {
|
||||||
|
|
||||||
|
Set<Class<?>> annotatedPublishers;
|
||||||
|
|
||||||
|
try (ScanResult result = new ClassGraph().enableClassInfo().enableAnnotationInfo()
|
||||||
|
.addClassLoader(Thread.currentThread().getContextClassLoader()).scan()) {
|
||||||
|
|
||||||
|
ClassInfoList classInfos = result.getClassesWithAnnotation(SmartgearsProfilePublisher.class.getName());
|
||||||
|
|
||||||
|
annotatedPublishers = classInfos.stream().map(ClassInfo::loadClass)
|
||||||
|
.filter(c -> Publisher.class.isAssignableFrom(c)).collect(Collectors.toSet());
|
||||||
|
|
||||||
|
}
|
||||||
/*
|
/*
|
||||||
@Override
|
* Collection<URL> urls =
|
||||||
public RegistryPublisher publisherFor(ContainerContext context) {
|
* ClasspathHelper.forClassLoader(Thread.currentThread().getContextClassLoader()
|
||||||
return context.configuration().mode()==Mode.online?
|
* ); urls.removeIf(url -> url.toString().endsWith(".so") ||
|
||||||
RegistryPublisherFactory.create(): new OfflinePublisher();
|
* url.toString().endsWith(".zip") );
|
||||||
}
|
*
|
||||||
|
*
|
||||||
|
* ConfigurationBuilder reflectionConf = new
|
||||||
|
* ConfigurationBuilder().addUrls(urls).setScanners(new
|
||||||
|
* TypeAnnotationsScanner(), new SubTypesScanner());
|
||||||
|
*
|
||||||
|
* Reflections reflection = new Reflections(reflectionConf);
|
||||||
|
*
|
||||||
|
* = reflection.getTypesAnnotatedWith(SmartgearsProfilePublisher.class);
|
||||||
|
*/
|
||||||
|
|
||||||
@Override
|
List<Publisher> foundPublishers = new ArrayList<Publisher>();
|
||||||
public RegistryPublisher publisherFor(ApplicationContext context) {
|
for (Class<?> annotatedPublisher : annotatedPublishers) {
|
||||||
return context.configuration().mode()==Mode.online?
|
try {
|
||||||
RegistryPublisherFactory.create(): new OfflinePublisher();
|
foundPublishers.add((Publisher) annotatedPublisher.getDeclaredConstructor().newInstance());
|
||||||
}*/
|
log.info("added class {} to publishers", annotatedPublisher);
|
||||||
|
} catch (Throwable e) {
|
||||||
@Override
|
log.error("publisher class {} cannot be instantiated", annotatedPublisher.getCanonicalName(), e);
|
||||||
public ScopedPublisher publisherFor(ContainerContext context) {
|
|
||||||
return context.configuration().mode()==Mode.online? RegistryPublisherFactory.scopedPublisher()
|
|
||||||
: new OfflinePublisher();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ScopedPublisher publisherFor(ApplicationContext context) {
|
|
||||||
return context.configuration().mode()==Mode.online? RegistryPublisherFactory.scopedPublisher()
|
|
||||||
: new OfflinePublisher();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public AuthorizationProxy authorizationProxy() {
|
|
||||||
return authorizationService();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
this.publishers = foundPublishers;
|
||||||
|
|
||||||
|
if (foundPublishers.isEmpty())
|
||||||
|
log.warn("no publishers found in classloader");
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.publishers;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SmartgearsConfiguration smartgearsConfiguration() {
|
||||||
|
ContainerConfigurationBinder binder = new ContainerConfigurationBinder();
|
||||||
|
return binder.loadSmartgearsProperty();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @Override public AuthorizationProvider authorizationProvider() { return
|
||||||
|
* containerContext.authorizationProvider(); }
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,15 +1,16 @@
|
||||||
package org.gcube.smartgears.provider;
|
package org.gcube.smartgears.provider;
|
||||||
|
|
||||||
import javax.servlet.ServletContext;
|
import java.util.List;
|
||||||
|
|
||||||
import org.gcube.common.authorization.client.proxy.AuthorizationProxy;
|
import jakarta.servlet.ServletContext;
|
||||||
import org.gcube.informationsystem.publisher.ScopedPublisher;
|
|
||||||
import org.gcube.smartgears.configuration.application.ApplicationExtensions;
|
import org.gcube.smartgears.configuration.SmartgearsConfiguration;
|
||||||
import org.gcube.smartgears.configuration.application.ApplicationHandlers;
|
import org.gcube.smartgears.configuration.application.ApplicationHandlers;
|
||||||
import org.gcube.smartgears.configuration.container.ContainerHandlers;
|
|
||||||
import org.gcube.smartgears.configuration.library.SmartGearsConfiguration;
|
|
||||||
import org.gcube.smartgears.context.application.ApplicationContext;
|
import org.gcube.smartgears.context.application.ApplicationContext;
|
||||||
import org.gcube.smartgears.context.container.ContainerContext;
|
import org.gcube.smartgears.context.container.ContainerContext;
|
||||||
|
import org.gcube.smartgears.extensions.ApplicationExtension;
|
||||||
|
import org.gcube.smartgears.handlers.container.ContainerHandler;
|
||||||
|
import org.gcube.smartgears.publishing.Publisher;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides dependencies for container and application management.
|
* Provides dependencies for container and application management.
|
||||||
|
@ -24,8 +25,9 @@ public interface Provider {
|
||||||
/**
|
/**
|
||||||
* Returns the runtime properties.
|
* Returns the runtime properties.
|
||||||
* @return the properties.
|
* @return the properties.
|
||||||
*/
|
|
||||||
SmartGearsConfiguration smartgearsConfiguration();
|
SmartGearsConfiguration smartgearsConfiguration();
|
||||||
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Assembles and returns the context of the container.
|
* Assembles and returns the context of the container.
|
||||||
|
@ -37,15 +39,14 @@ public interface Provider {
|
||||||
* Returns the handlers associated with the container.
|
* Returns the handlers associated with the container.
|
||||||
* @return the handlers
|
* @return the handlers
|
||||||
*/
|
*/
|
||||||
ContainerHandlers containerHandlers();
|
List<ContainerHandler> containerHandlers();
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns an implementation of the IS publisher for the container
|
* Returns an implementation of the IS publisher for the container
|
||||||
* @param application the context of the container
|
|
||||||
* @return the publisher implementation
|
* @return the publisher implementation
|
||||||
*/
|
*/
|
||||||
ScopedPublisher publisherFor(ContainerContext application);
|
List<Publisher> publishers();
|
||||||
|
|
||||||
//application-level dependencies
|
//application-level dependencies
|
||||||
|
|
||||||
|
@ -65,25 +66,8 @@ public interface Provider {
|
||||||
*/
|
*/
|
||||||
ApplicationHandlers handlersFor(ApplicationContext application);
|
ApplicationHandlers handlersFor(ApplicationContext application);
|
||||||
|
|
||||||
/**
|
List<ApplicationExtension> extensionsFor(ApplicationContext application);
|
||||||
* Returns the API extensions associated with a given application.
|
|
||||||
* @param application the context of the application
|
|
||||||
* @return the extensions
|
|
||||||
*/
|
|
||||||
ApplicationExtensions extensionsFor(ApplicationContext application);
|
|
||||||
|
|
||||||
/**
|
SmartgearsConfiguration smartgearsConfiguration();
|
||||||
* Returns an implementation of the IS publisher for a given application
|
|
||||||
* @param application the context of the application
|
|
||||||
* @return the publisher implementation
|
|
||||||
*/
|
|
||||||
ScopedPublisher publisherFor(ApplicationContext application);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns an implementation of the IS publisher for a given application
|
|
||||||
* @param application the context of the application
|
|
||||||
* @return the publisher implementation
|
|
||||||
*/
|
|
||||||
AuthorizationProxy authorizationProxy();
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,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,77 @@
|
||||||
|
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.factories.AuthorizationProvider;
|
||||||
|
import org.gcube.common.security.secrets.Secret;
|
||||||
|
import org.gcube.common.security.secrets.UmaTokenSecret;
|
||||||
|
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.debug("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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
|
public SimpleCredentials getCredentials() {
|
||||||
|
return credentials;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,43 @@
|
||||||
|
package org.gcube.smartgears.security.defaults;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.gcube.common.security.credentials.Credentials;
|
||||||
|
import org.gcube.common.security.factories.AuthorizationProviderFactory;
|
||||||
|
import org.gcube.common.validator.ValidationError;
|
||||||
|
import org.gcube.common.validator.ValidatorFactory;
|
||||||
|
import org.gcube.common.validator.annotations.NotEmpty;
|
||||||
|
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");
|
||||||
|
List<ValidationError> errors = ValidatorFactory.validator().validate(credentials);
|
||||||
|
if (!errors.isEmpty())
|
||||||
|
throw new IllegalArgumentException(String.format("invalid credential: %s", errors));
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,28 @@
|
||||||
|
package org.gcube.smartgears.security.secrets;
|
||||||
|
|
||||||
|
import org.gcube.common.security.secrets.UmaTokenSecret;
|
||||||
|
import org.gcube.smartgears.Constants;
|
||||||
|
import org.gcube.smartgears.security.secrets.exceptions.SecretNotFoundException;
|
||||||
|
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
|
||||||
|
public class GCubeKeyCloakSecretFactory implements SecretFactory<UmaTokenSecret> {
|
||||||
|
|
||||||
|
private static final String BEARER_AUTH_PREFIX ="Bearer";
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public UmaTokenSecret create(HttpServletRequest request) throws SecretNotFoundException {
|
||||||
|
String authHeader = request.getHeader(Constants.authorization_header);
|
||||||
|
String umaToken = null;
|
||||||
|
if (authHeader!=null && !authHeader.isEmpty() && authHeader.startsWith(BEARER_AUTH_PREFIX)) {
|
||||||
|
umaToken = authHeader.substring(BEARER_AUTH_PREFIX.length()).trim();
|
||||||
|
return new UmaTokenSecret(umaToken);
|
||||||
|
} else throw new SecretNotFoundException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class<UmaTokenSecret> getSecretClass() {
|
||||||
|
return UmaTokenSecret.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,26 @@
|
||||||
|
package org.gcube.smartgears.security.secrets;
|
||||||
|
|
||||||
|
import static org.gcube.smartgears.Constants.token_header;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
import org.gcube.common.security.secrets.GCubeSecret;
|
||||||
|
import org.gcube.smartgears.security.secrets.exceptions.SecretNotFoundException;
|
||||||
|
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
|
||||||
|
public class LegacyGCubeTokenSecretFactory implements SecretFactory<GCubeSecret> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public GCubeSecret create(HttpServletRequest request) throws SecretNotFoundException {
|
||||||
|
String token = request.getParameter(token_header)==null? request.getHeader(token_header):request.getParameter(token_header);
|
||||||
|
if (Objects.isNull(token) || token.isBlank()) throw new SecretNotFoundException();
|
||||||
|
return new GCubeSecret(token);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class<GCubeSecret> getSecretClass() {
|
||||||
|
return GCubeSecret.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,14 @@
|
||||||
|
package org.gcube.smartgears.security.secrets;
|
||||||
|
|
||||||
|
import org.gcube.common.security.secrets.Secret;
|
||||||
|
import org.gcube.smartgears.security.secrets.exceptions.SecretNotFoundException;
|
||||||
|
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
|
||||||
|
public interface SecretFactory<T extends Secret> {
|
||||||
|
|
||||||
|
Class<T> getSecretClass();
|
||||||
|
|
||||||
|
T create(HttpServletRequest request) throws SecretNotFoundException;
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
package org.gcube.smartgears.security.secrets.exceptions;
|
||||||
|
|
||||||
|
public class SecretNotFoundException extends Exception {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
}
|
|
@ -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,40 +1,37 @@
|
||||||
package org.gcube.smartgears.utils;
|
package org.gcube.smartgears.utils;
|
||||||
|
|
||||||
import org.gcube.common.authorization.library.provider.CalledMethodProvider;
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
public class InnerMethodName {
|
public class InnerMethodName {
|
||||||
|
|
||||||
public static InnerMethodName instance = new InnerMethodName();
|
private static Logger logger = LoggerFactory.getLogger(InnerMethodName.class);
|
||||||
|
|
||||||
private static Logger logger = LoggerFactory.getLogger(CalledMethodProvider.class);
|
|
||||||
|
|
||||||
// Thread local variable containing each thread's ID
|
// Thread local variable containing each thread's ID
|
||||||
private static final InheritableThreadLocal<String> threadMethod =
|
private static final InheritableThreadLocal<String> threadMethod =
|
||||||
new InheritableThreadLocal<String>() {
|
new InheritableThreadLocal<String>() {
|
||||||
|
|
||||||
@Override protected String initialValue() {
|
@Override protected String initialValue() {
|
||||||
return "UNKNOWN";
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
private InnerMethodName(){}
|
private InnerMethodName(){}
|
||||||
|
|
||||||
public String get(){
|
public static String get(){
|
||||||
String calledMethod = threadMethod.get();
|
String calledMethod = threadMethod.get();
|
||||||
logger.trace("getting InnerMethodName as "+calledMethod+" in thread "+Thread.currentThread().getId() );
|
logger.trace("getting InnerMethodName as "+calledMethod+" in thread "+Thread.currentThread().getId() );
|
||||||
return calledMethod;
|
return calledMethod;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void set(String calledMethod){
|
public static void set(String calledMethod){
|
||||||
if (calledMethod==null) return;
|
if (calledMethod==null) return;
|
||||||
threadMethod.set(calledMethod);
|
threadMethod.set(calledMethod);
|
||||||
logger.trace("setting InnerMethodName as "+calledMethod+" in thread "+Thread.currentThread().getId() );
|
logger.trace("setting InnerMethodName as "+calledMethod+" in thread "+Thread.currentThread().getId() );
|
||||||
}
|
}
|
||||||
|
|
||||||
public void reset(){
|
public static void reset(){
|
||||||
threadMethod.remove();
|
threadMethod.remove();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,8 +16,8 @@ import java.util.Collection;
|
||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
import java.util.concurrent.ScheduledExecutorService;
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
import org.gcube.common.authorization.library.provider.ServiceIdentifier;
|
import org.gcube.common.authorization.library.provider.ServiceIdentifier;
|
||||||
import org.gcube.common.authorization.library.provider.ServiceInfo;
|
import org.gcube.common.authorization.library.provider.ServiceInfo;
|
||||||
|
@ -214,7 +214,7 @@ public class Utils {
|
||||||
public static ServiceInfo getServiceInfo(ApplicationContext application){
|
public static ServiceInfo getServiceInfo(ApplicationContext application){
|
||||||
String hostedin = String.format("%s_%d", application.container().configuration().hostname(), application.container().configuration().port());
|
String hostedin = String.format("%s_%d", application.container().configuration().hostname(), application.container().configuration().port());
|
||||||
return
|
return
|
||||||
new ServiceInfo(new ServiceIdentifier(application.configuration().serviceClass(), application.configuration().name(), hostedin));
|
new ServiceInfo(new ServiceIdentifier(application.configuration().group(), application.configuration().name(), hostedin));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Throwable getCause(Throwable e) {
|
public static Throwable getCause(Throwable e) {
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
/smartgears-config.xml
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue