Compare commits

...

94 Commits

Author SHA1 Message Date
lucio 38874c9529 repository related classes updated 2024-04-05 21:11:04 +02:00
lucio 32b35e4060 changes on handlers 2024-04-01 19:29:23 +02:00
lucio 8df806bf49 bug on geUser solved 2024-03-28 08:35:15 +01:00
lucio 26bc4c93ac Handler fro user and group extracted from managers 2024-03-27 22:23:30 +01:00
lucio 335204d3ee docker info updated 2024-03-27 12:04:49 +01:00
lucio 4878f8bb18 updated 2024-03-25 16:37:40 +01:00
lucio eefa46cbf6 warnings removed 2024-03-15 15:14:26 +01:00
lucio e11b2147da porting to jakarta 2024-03-15 14:26:05 +01:00
lucio 0becded125 checks updated 2024-01-24 16:32:18 +01:00
lucio c4d5cffe02 moved to new ceph storage 2024-01-19 12:20:19 +01:00
lucio f75f7d86d9 jdbc driver updated 2023-12-01 13:04:07 +01:00
lucio 2452a25349 changelog updated 2023-06-01 19:06:05 +02:00
lucio 87cc8a3ff9 - managing of vre folder specific backend 2023-06-01 19:00:42 +02:00
lucio b34ad84baf updated 2023-05-30 11:08:31 +02:00
lucio 7e875a5dfb added Docs to root application 2023-05-30 10:46:38 +02:00
lucio 10982ea64d added correct exclude 2023-05-30 10:37:02 +02:00
lucio a0cd2e8ccf enunciate improved 2023-05-30 10:18:47 +02:00
lucio e5dda6bb8b enunciate docs added 2023-05-22 14:44:51 +02:00
lucio d1d45a8056 script utils version updated 2023-05-22 13:19:46 +02:00
lucio 56f8ffb838 updated 2023-05-22 11:02:21 +02:00
Lucio Lelii d216459747 acl control added 2023-05-14 12:57:32 +02:00
lucio 4d118372f3 solved bug on archive upload 2023-05-09 15:46:34 +02:00
lucio 0cc0949698 updated 2023-05-05 22:01:42 +02:00
lucio 884f40b759 app configuration updated 2023-05-05 21:53:27 +02:00
lucio a1b69aee6a update 2023-05-05 15:58:13 +02:00
lucio 09879535d2 added application.yaml 2023-02-13 11:16:44 +01:00
lucio 7d96327512 updated for changes on smartgears 2023-01-20 13:36:28 +01:00
Lucio Lelii 443d9cabd4 version of jackrabbit moved to the latest stable 2022-12-23 15:19:29 +01:00
Lucio Lelii 2629c5c387 updated 2022-12-21 19:17:06 +01:00
Lucio Lelii 3a7aa8b8e3 test on container added 2022-12-19 17:47:39 +01:00
Lucio Lelii d0a7197c5c solved issue on duration 2022-12-15 15:36:12 +01:00
Lucio Lelii 0420e2ba3e added fields to ScriptStatus 2022-12-15 15:24:30 +01:00
Lucio Lelii 2033a4b79f added status for script execution 2022-12-15 12:08:39 +01:00
Lucio Lelii bca553aa5f changes 2022-12-14 14:52:27 +01:00
Lucio Lelii 4bd37f8963 remove specific version added 2022-12-07 11:59:02 +01:00
Lucio Lelii b3913ba9c1 added method for version removal 2022-12-06 16:49:41 +01:00
Lucio Lelii 1f6329c38e added possibility to set owner on backends 2022-12-02 14:39:37 +01:00
Lucio Lelii 4083b7c120 TODO for accounting 2022-11-30 17:51:50 +01:00
Lucio Lelii a500df61a1 excluded VREFolders from renaming 2022-11-30 11:16:02 +01:00
Lucio Lelii 7019740af7 enabled renaming of SharedFodler 2022-11-30 11:06:49 +01:00
Lucio Lelii 2012500de8 added check on id exists 2022-11-24 14:29:41 +01:00
Lucio Lelii 8b235da142 changes on StorageBachend interface 2022-11-22 14:05:31 +01:00
Lucio Lelii 0649acb8a9 solved a bug on internal file creation 2022-11-22 11:52:40 +01:00
Lucio Lelii 2e7fc876cf adde methdo for scripts 2022-11-21 16:15:32 +01:00
Lucio Lelii 9b568a09ec Content handler modified 2022-11-18 17:24:25 +01:00
Lucio Lelii 55b6d8e09a removed unused files 2022-11-18 09:29:23 +01:00
Lucio Lelii e60a07abe9 ingore update 2022-11-18 09:27:23 +01:00
Lucio Lelii 1525afef9e removed uned class 2022-11-18 09:26:04 +01:00
Lucio Lelii fad2e7ffb9 removed old files 2022-11-18 09:24:54 +01:00
Lucio Lelii b625fafcc8 improve upload speed 2022-11-17 17:14:51 +01:00
Lucio Lelii 80d15ccef7 changes 2022-11-16 17:50:00 +01:00
Lucio Lelii 6d72896662 pom updated 2022-11-16 09:28:12 +01:00
Lucio Lelii a87d6ab3da update 2022-11-15 17:55:31 +01:00
Lucio Lelii 3b5686e705 update aspectj plugin dependency 2022-11-15 10:37:11 +01:00
Lucio Lelii d36a3314ba issue on voaltile links solved 2022-11-11 16:09:50 +01:00
Lucio Lelii 6dd371070e updated pom to include lastest tika 2022-11-11 11:34:20 +01:00
Lucio Lelii 6af9fce70f Merge branch 'multipleStorageBackends' of https://code-repo.d4science.org/gCubeSystem/storagehub.git into multipleStorageBackends 2022-11-04 15:51:57 +01:00
Lucio Lelii ac2ca4c360 updated tika library 2022-11-04 15:24:17 +01:00
Lucio Lelii b5b3669af5 bug on public link solved 2022-10-17 15:27:40 +02:00
Lucio Lelii 88406a3bf2 solved big on home update 2022-10-04 13:44:04 +02:00
Lucio Lelii 6756c2890c Merge branch 'multipleStorageBackends' of https://code-repo.d4science.org/gCubeSystem/storagehub into multipleStorageBackends 2022-10-04 11:41:30 +02:00
Lucio Lelii 4d38cc6e72 update user created 2022-10-03 17:24:53 +02:00
Lucio Lelii e1db5df7c9 ScritpUtil updated 2022-09-28 19:21:49 +02:00
Lucio Lelii 25105ca041 adding enunciate 2022-09-22 16:00:30 +02:00
Lucio Lelii 5de8dee586 added notification client to AppManager 2022-09-12 16:56:11 +02:00
Lucio Lelii 3e6e203f36 update 2022-09-12 15:00:23 +02:00
Lucio Lelii bfa702bf0f download folder modified 2022-09-06 17:11:27 +02:00
Lucio Lelii 50124d8a49 volatile area with public link added 2022-09-01 17:15:03 +02:00
Lucio Lelii 9dea04e74e Merge branch 'multipleStorageBackends' of https://code-repo.d4science.org/gCubeSystem/storagehub.git into multipleStorageBackends 2022-08-30 16:38:34 +02:00
Lucio Lelii 28044da030 pom updated 2022-08-30 16:38:05 +02:00
Lucio Lelii b0141e6b6f storage manager libraries updated 2022-08-05 14:16:19 +02:00
Lucio Lelii 14a71d4aa7 docker folder updated 2022-07-22 10:34:01 +02:00
Lucio Lelii 3b0bb084b6 java melody removed 2022-07-22 10:33:12 +02:00
Lucio Lelii c4ea5bb05c solved bug on initalization 2022-06-27 15:34:24 +02:00
Lucio Lelii ce071c1f7e conf updated 2022-06-22 18:51:18 +02:00
Lucio Lelii 805b72155d Merge branch 'multipleStorageBackends' of
https://code-repo.d4science.org/gCubeSystem/storagehub.git into
multipleStorageBackends

Conflicts:
	docker-compose.yml
	src/main/webapp/WEB-INF/README
	src/test/java/org/gcube/data/access/fs/container/CreateUsers.java
	src/test/resources/compose-test.yml
2022-06-16 12:35:19 +02:00
Lucio Lelii e43faf6f92 changes 2022-06-16 12:17:21 +02:00
Lucio Lelii 492873bd7e porting to smartgears 4 2022-06-15 17:49:58 +02:00
Lucio Lelii d2b3151edc update 2022-03-28 18:27:18 +02:00
Lucio Lelii 9d3bd619bd added init script if repository is not yet initialized 2022-02-05 11:42:41 +01:00
Lucio Lelii 6d3e9394c4 docker files added 2022-02-02 11:27:52 +01:00
Lucio Lelii d672386824 added docker files for tests 2022-02-02 11:27:00 +01:00
Lucio Lelii 57e0113216 new feature for PayloadBackend added 2021-12-23 17:26:30 +01:00
Lucio Lelii 4f87677674 Minio integration 2021-12-03 16:55:54 +01:00
Lucio Lelii e11bb536a7 a part of s3StorageIntegration 2021-11-26 17:49:35 +01:00
lucio.lelii af9290cbca check for folder connector with same name 2021-10-28 15:50:56 +02:00
lucio.lelii db30621608 success set on users add to group 2021-10-26 14:47:55 +02:00
Lucio Lelii 70391906e2 update 2021-10-25 17:39:12 +02:00
Lucio Lelii ca23f94e09 ManageBy info added 2021-10-25 16:16:26 +02:00
Lucio Lelii 8d11063f6b Added some fix 2021-10-18 16:11:49 +02:00
lucio.lelii 9facccdf46 upload by url added 2021-10-15 19:51:57 +02:00
lucio.lelii da7385f62f pom update 2021-10-15 13:20:06 +02:00
lucio.lelii 29b728b057 reverted last commit 2021-10-15 12:00:09 +02:00
lucio.lelii 7ee17adeac upload archive session is not saved until finished 2021-10-15 11:51:27 +02:00
143 changed files with 7496 additions and 3613 deletions

View File

@ -1,40 +1,40 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" output="target/classes" path="src/main/java">
<attributes>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry excluding="**" kind="src" output="target/classes" path="src/main/resources">
<attributes>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="src" output="target/test-classes" path="src/test/java">
<attributes>
<attribute name="test" value="true"/>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry excluding="**" kind="src" output="target/test-classes" path="src/test/resources">
<attributes>
<attribute name="test" value="true"/>
<attribute name="maven.pomderived" value="true"/>
<attribute name="optional" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
<attributes>
<attribute name="maven.pomderived" value="true"/>
<attribute name="org.eclipse.jst.component.dependency" value="/WEB-INF/lib"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8">
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-17">
<attributes>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry combineaccessrules="false" kind="src" path="/storagehub-model"/>
<classpathentry kind="src" output="target/classes" path="src/main/java">
<attributes>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="src" output="target/test-classes" path="src/test/java">
<attributes>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
<attribute name="test" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="output" path="target/classes"/>
</classpath>

2
.gitignore vendored
View File

@ -1 +1,3 @@
target
/Storagehub-TODO
/postgres-data/

View File

@ -1,8 +1,11 @@
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
org.eclipse.jdt.core.compiler.compliance=1.8
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
org.eclipse.jdt.core.compiler.codegen.targetPlatform=17
org.eclipse.jdt.core.compiler.compliance=17
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=ignore
org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=warning
org.eclipse.jdt.core.compiler.release=disabled
org.eclipse.jdt.core.compiler.source=1.8
org.eclipse.jdt.core.compiler.source=17

View File

@ -1,5 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?><project-modules id="moduleCoreId" project-version="1.5.0">
@ -23,7 +40,24 @@
<wb-module deploy-name="storagehub">
@ -47,7 +81,24 @@
<wb-resource deploy-path="/" source-path="/target/m2e-wtp/web-resources"/>
@ -71,61 +122,79 @@
<wb-resource deploy-path="/" source-path="/src/main/webapp" tag="defaultRootSource"/>
<wb-resource deploy-path="/WEB-INF/classes" source-path="/src/main/java"/>
<wb-resource deploy-path="/WEB-INF/classes" source-path="/src/main/resources"/>
<dependent-module archiveName="storagehub-model-1.1.0-SNAPSHOT.jar" deploy-path="/WEB-INF/lib" handle="module:/resource/storagehub-model/storagehub-model">
<wb-resource deploy-path="/WEB-INF/classes" source-path="/src/main/java"/>
<wb-resource deploy-path="/WEB-INF/classes" source-path="/src/test/java"/>
<dependent-module archiveName="common-smartgears-app-3.0.1-SNAPSHOT.jar" deploy-path="/WEB-INF/lib" handle="module:/resource/common-smartgears-app/common-smartgears-app">
<dependency-type>uses</dependency-type>
</dependent-module>
<dependent-module archiveName="storagehub-script-utils-1.0.0.jar" deploy-path="/WEB-INF/lib" handle="module:/resource/storagehub-scripting-util/storagehub-scripting-util">
<dependent-module archiveName="authorization-control-library-2.0.0-SNAPSHOT.jar" deploy-path="/WEB-INF/lib" handle="module:/resource/authorization-control-library/authorization-control-library">
<dependency-type>uses</dependency-type>
</dependent-module>
<dependent-module archiveName="storagehub-model-2.0.0-SNAPSHOT.jar" deploy-path="/WEB-INF/lib" handle="module:/resource/storagehub-model/storagehub-model">
<dependency-type>uses</dependency-type>
</dependent-module>
<dependent-module archiveName="storagehub-script-utils-2.0.0-SNAPSHOT.jar" deploy-path="/WEB-INF/lib" handle="module:/resource/storagehub-scripting-util/storagehub-scripting-util">
<dependency-type>uses</dependency-type>
</dependent-module>
@ -149,7 +218,24 @@
<property name="context-root" value="storagehub"/>
@ -173,7 +259,24 @@
<property name="java-output-path" value="/storagehub-webapp_BRANCH/target/classes"/>
@ -197,7 +300,24 @@
</wb-module>

View File

@ -1,8 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<faceted-project>
<fixed facet="wst.jsdt.web"/>
<installed facet="java" version="1.8"/>
<installed facet="jst.web" version="3.0"/>
<installed facet="jst.jaxrs" version="2.0"/>
<installed facet="wst.jsdt.web" version="1.0"/>
<installed facet="jst.web" version="4.0"/>
<installed facet="java" version="17"/>
</faceted-project>

View File

@ -1,15 +1,22 @@
# Changelog
# Changelog for "storagehub"
All notable changes to this project will be documented in this file.
This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [v1.4.0] - [2021-10-07]
## [v1.5.0-SNAPSHOT] 2021-10-15
- minio as default storage
- vre folders can define specific bucket as backend
- enunciate docs
- dockerization of the service
## [v1.4.0] 2021-10-07
- slow query removed from VRE retrieving and recents
- incident #22184 solved
- incident solved [#22184]
## [v1.3.2] - [2021-09-28]
- fix 22087
- fix 22087
## [v1.3.1] - [2021-09-08]
@ -17,7 +24,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
## [v1.3.0] - [2021-03-31]
- possibility to impersonate people added
possibility to impersonate people added
## [v1.2.5] - [2021-03-11]
@ -41,8 +48,6 @@ method for description update added
bug on Archive uploader solved
## [v1.2.0] - [2020-04-15]
trash items changes owner on restore
@ -51,20 +56,14 @@ restore with new destination folder added
move between shared and private or different shared folder enabled
## [v1.0.8] - [2019-09-20]
Bug on ushare owner fixed
## [v1.0.5] - [2019-04-04]
Active wait for lock in case of item creation added
## [v1.0.0] - [2015-07-01]
First commit

22
DOCKER-INSTRUCTION.md Normal file
View File

@ -0,0 +1,22 @@
# Docker Instruction
Instruction to generate e run storagehub docker image
## Dockerfile - DokerCompose
This image is ready to be deployed in a new environment.
The Dockerfile generate an image without configurations (container, service etc.), all the configurations must be provided at image start time.
In fact the docker-compose.yml requires 3 environmental variables set at start time: APP_PORT, JACKRABBIT_FOLDER, CONTAINER_SERVICE_FILE_FOLDER.
```
APP_PORT=8080 JACKRABBIT_FOLDER=/data/jackrabbit CONTAINER_SERVICE_FILE_FOLDER=/etc/smartgears-config docker compose up
```
## Dockerfile - DokerCompose standalone
The image generated from Dockerfile-standalone contains all the configuration to run on a fully isolated container.
The docker-compose-standalone.yml contains the declaration of all the services needed (postgres and minio) teking all the configuration from the local ./docker folder
```
docker compose -f docker-compose-standalone.yml up
```

4
Dockerfile Normal file
View File

@ -0,0 +1,4 @@
FROM d4science/smartgears-distribution:4.0.0-SNAPSHOT-java17-tomcat10.1.19
COPY ./target/storagehub.war /tomcat/webapps/
COPY ./docker/jackrabbit/bootstrap.properties /app/jackrabbit/
COPY ./docker/storagehub.xml /tomcat/conf/Catalina/localhost/

13
Dockerfile-local Normal file
View File

@ -0,0 +1,13 @@
FROM d4science/smartgears-distribution:4.0.0-SNAPSHOT-java17-tomcat10.1.19
#install unzip
RUN apt-get update && apt-get install unzip
COPY ./target/storagehub-test-storages.war /tomcat/webapps/storagehub.war
COPY ./docker/jackrabbit /app/jackrabbit
COPY ./docker/storagehub.xml /tomcat/conf/Catalina/localhost/
COPY ./docker/logback.xml /etc/
COPY ./docker/local/container.ini /etc/
RUN unzip /tomcat/webapps/storagehub.war -d /tomcat/webapps/storagehub
RUN rm /tomcat/webapps/storagehub.war
#COPY ./docker/local/storage-settings.properties /tomcat/webapps/storagehub/WEB-INF/classes/

8
Dockerfile-standalone Normal file
View File

@ -0,0 +1,8 @@
FROM d4science/smartgears-distribution:4.0.0-SNAPSHOT-java17-tomcat10.1.19
COPY ./target/storagehub.war /tomcat/webapps/
COPY ./docker/jackrabbit /app/jackrabbit
COPY ./docker/storagehub.xml /tomcat/conf/Catalina/localhost/
COPY ./docker/logback.xml /etc/
COPY ./docker/container.ini /etc/
RUN mkdir -p /etc/config/StorageHub
COPY ./docker/storage-settings.properties /etc/config/StorageHub/

3
ToRemoveOnImport Normal file
View File

@ -0,0 +1,3 @@
nodeType to remove on new import from a backup:
externalUrl

15
buildImageAndStart.sh Executable file
View File

@ -0,0 +1,15 @@
#!/bin/bash
set -e
NAME=storagehub
PORT=8100
DEBUG_PORT=5005
debug=false
compile=false
mvn clean package
docker-compose -f docker-compose-standalone.yml build
docker-compose -f docker-compose-standalone.yml up

View File

@ -1 +0,0 @@
${gcube.license}

View File

@ -1,66 +0,0 @@
The gCube System - ${name}
--------------------------------------------------
${description}
${gcube.description}
${gcube.funding}
Version
--------------------------------------------------
${version} (${buildDate})
Please see the file named "changelog.xml" in this directory for the release notes.
Authors
--------------------------------------------------
* Lucio Lelii (lucio.lelii-AT-isti.cnr.it), CNR Pisa,
Istituto di Scienza e Tecnologie dell'Informazione "A. Faedo".
Maintainers
-----------
* Lucio Lelii (lucio.lelii-AT-isti.cnr.it), CNR Pisa,
Istituto di Scienza e Tecnologie dell'Informazione "A. Faedo".
Download information
--------------------------------------------------
Source code is available from SVN:
${scm.url}
Binaries can be downloaded from the gCube website:
${gcube.website}
Installation
--------------------------------------------------
Installation documentation is available on-line in the gCube Wiki:
${gcube.wikiRoot}/Home_Library_2.0_API_Framework_Specification
Documentation
--------------------------------------------------
Documentation is available on-line in the gCube Wiki:
${gcube.wikiRoot}/StorageHub_API_Framework_Specification
Support
--------------------------------------------------
Bugs and support requests can be reported in the gCube issue tracking tool:
${gcube.issueTracking}
Licensing
--------------------------------------------------
This software is licensed under the terms you may find in the file named "LICENSE" in this directory.

View File

@ -1,7 +0,0 @@
<application mode='online'>
<name>StorageHub</name>
<group>DataAccess</group>
<version>${version}</version>
<description>Storage Hub webapp</description>
<local-persistence location='target' />
</application>

50
docker-compose-local.yml Normal file
View File

@ -0,0 +1,50 @@
version: '3.7'
services:
elb:
image: haproxy
ports:
- "8100:8100"
volumes:
- ./docker/haproxy:/usr/local/etc/haproxy
postgres:
image: postgres:10.5
restart: always
environment:
- POSTGRES_DB=workspace-db
- POSTGRES_USER=ws-db-user
- POSTGRES_PASSWORD=dbPwd
logging:
options:
max-size: 10m
max-file: "3"
ports:
- '5423:5432'
volumes:
- ./postgres-data:/var/lib/postgresql/data
- ./sql/create_tables.sql:/docker-entrypoint-initdb.d/create_tables.sql
storagehub:
build:
dockerfile: ./Dockerfile-local
ports:
- '8080:8080'
- '4954:4954'
environment:
- ADMINISTRATION_PORT_ENABLED=true
- DOMAIN_NAME=docker_domain
- JPDA_OPTS="-agentlib:jdwp=transport=dt_socket,address=0.0.0.0:4954,server=y,suspend=n"
- JPDA_ADDRESS=*:4954
minio:
image: minio/minio
ports:
- "9000:9000"
- "9001:9001"
volumes:
- minio_storage:/data
environment:
MINIO_ROOT_USER: SHUBTEST
MINIO_ROOT_PASSWORD: wJalrXUtnFEMI/K7MDENG/bPxRfiCY
command: server --console-address ":9001" /data
volumes:
minio_storage: {}

View File

@ -0,0 +1,45 @@
version: '3.7'
services:
postgres:
image: postgres:16.2
restart: always
environment:
- POSTGRES_DB=workspace-db
- POSTGRES_USER=ws-db-user
- POSTGRES_PASSWORD=dbPwd
logging:
options:
max-size: 10m
max-file: "3"
ports:
- '5423:5432'
volumes:
- ./data/postgres-data:/var/lib/postgresql/data
copy the sql script to create tables
- ./data/sql/create_tables.sql:/docker-entrypoint-initdb.d/create_tables.sql
storagehub:
build:
dockerfile: Dockerfile-standalone
environment:
_JAVA_OPTIONS:
-Xdebug
-agentlib:jdwp=transport=dt_socket,server=y,suspend=${SUSPEND:-n},address=*:5005
ports:
- '8081:8080'
- '5005:5005'
minio:
image: minio/minio
ports:
- "9000:9000"
- "9001:9001"
volumes:
- minio_storage:/data
environment:
MINIO_ROOT_USER: SHUBTEST
MINIO_ROOT_PASSWORD: wJalrXUtnFEMI/K7MDENG/bPxRfiCY
command: server --console-address ":9001" /data
volumes:
minio_storage: {}

10
docker-compose.yml Normal file
View File

@ -0,0 +1,10 @@
version: '3.7'
services:
storagehub:
image: d4science/staragehub:latest
ports:
- '${APP_PORT}:8080'
volumes:
- ${JACKRABBIT_FOLDER}:/app/jackrabbit
- ${SMARTGEARS_CONFIG_FOLDER}:/etc

23
docker/container.ini Normal file
View File

@ -0,0 +1,23 @@
[node]
mode = offline
hostname = dlib29.isti.cnr.it
protocol= http
port = 8080
infrastructure = gcube
authorizeChildrenContext = true
publicationFrequencyInSeconds = 60
[properties]
SmartGearsDistribution = 4.0.0-SNAPSHOT
SmartGearsDistributionBundle = UnBundled
[site]
country = it
location = pisa
[authorization]
factory = org.gcube.smartgears.security.defaults.DefaultAuthorizationProviderFactory
factory.endpoint = https://accounts.dev.d4science.org/auth/realms/d4science/protocol/openid-connect/token
credentials.class = org.gcube.smartgears.security.SimpleCredentials
credentials.clientID = node-whn-test-uno-d-d4s.d4science.org
credentials.secret = 979bd3bc-5cc4-11ec-bf63-0242ac130002

View File

@ -0,0 +1,18 @@
# haproxy.cfg
global
lua-load /usr/local/etc/haproxy/send_to_all_whnmanager.lua
frontend http
bind *:8100
mode http
timeout client 10s
http-request use-service lua.broadcast_to_nodes if { path /whn-manager meth PUT DELETE }
use_backend all
backend all
mode http
option httpchk
http-check send meth GET uri /storagehub/gcube/resource/health
http-check expect status 200
server s1 storagehub:8080 check

View File

@ -0,0 +1,21 @@
local function broadcast_to_nodes(req)
-- Get all servers in the backend
local servers = pxn.get_servers("all")
for _, server in ipairs(servers) do
-- Forward the request to each server
pxn.http_request({
"PUT", -- Method
server["address"], -- Address of the server
tonumber(server["port"]), -- Port of the server
req.method, -- HTTP method
req.uri, -- URI
req.headers, -- Headers
req.body -- Body
})
end
end
core.register_service("broadcast_to_nodes", "http", broadcast_to_nodes)

View File

@ -0,0 +1,11 @@
#bootstrap properties for the repository startup servlet.
#Fri Jul 21 05:19:29 CEST 2017
java.naming.factory.initial=org.apache.jackrabbit.core.jndi.provider.DummyInit$
repository.home=jackrabbit
rmi.enabled=true
repository.config=jackrabbit/repository.xml
repository.name=jackrabbit.repository
rmi.host=localhost
java.naming.provider.url=http\://www.apache.org/jackrabbit
jndi.enabled=true
rmi.port=0

View File

@ -0,0 +1,110 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Licensed to the Apache Software Foundation (ASF) under one or more contributor
license agreements. See the NOTICE file distributed with this work for additional
information regarding copyright ownership. The ASF licenses this file to
You under the Apache License, Version 2.0 (the "License"); you may not use
this file except in compliance with the License. You may obtain a copy of
the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required
by applicable law or agreed to in writing, software distributed under the
License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS
OF ANY KIND, either express or implied. See the License for the specific
language governing permissions and limitations under the License. -->
<!DOCTYPE Repository PUBLIC "-//The Apache Software Foundation//DTD Jackrabbit 2.0//EN" "http://jackrabbit.apache.org/dtd/repository-2.0.dtd">
<Repository>
<!-- virtual file system where the repository stores global state (e.g.
registered namespaces, custom node types, etc.) -->
<FileSystem class="org.apache.jackrabbit.core.fs.db.DbFileSystem">
<param name="driver" value="org.postgresql.Driver" />
<param name="schema" value="postgresql" />
<param name="url" value="jdbc:postgresql://postgres:5432/workspace-db" />
<param name="user" value="ws-db-user" />
<param name="password" value="dbPwd" />
<param name="schemaObjectPrefix" value="rep_" />
</FileSystem>
<!-- data store configuration -->
<DataStore class="org.apache.jackrabbit.core.data.db.DbDataStore">
<param name="driver" value="org.postgresql.Driver" />
<param name="databaseType" value="postgresql" />
<param name="url" value="jdbc:postgresql://postgres:5432/workspace-db" />
<param name="user" value="ws-db-user" />
<param name="password" value="dbPwd" />
<param name="minRecordLength" value="1024" />
<param name="maxConnections" value="3" />
<param name="copyWhenReading" value="true" />
<param name="tablePrefix" value="datastore_" />
<param name="schemaObjectPrefix" value="" />
</DataStore>
<!-- security configuration -->
<Security appName="Jackrabbit">
<SecurityManager class="org.apache.jackrabbit.core.DefaultSecurityManager" />
<AccessManager class="org.apache.jackrabbit.core.security.DefaultAccessManager" />
<LoginModule class="org.apache.jackrabbit.core.security.authentication.DefaultLoginModule">
<param name="adminId" value="admin" />
</LoginModule>
</Security>
<!-- location of workspaces root directory and name of default workspace -->
<Workspaces rootPath="${rep.home}/workspaces" defaultWorkspace="default" />
<Workspace name="${wsp.name}">
<FileSystem class="org.apache.jackrabbit.core.fs.local.LocalFileSystem">
<param name="path" value="${wsp.home}" />
</FileSystem>
<PersistenceManager class="org.apache.jackrabbit.core.persistence.pool.PostgreSQLPersistenceManager">
<param name="driver" value="org.postgresql.Driver" />
<param name="url" value="jdbc:postgresql://postgres:5432/workspace-db" />
<param name="schema" value="postgresql" />
<param name="user" value="ws-db-user" />
<param name="password" value="dbPwd" />
<param name="schemaObjectPrefix" value="pm_${wsp.name}_" />
<param name="bundleCacheSize" value="600" />
<param name="errorHandling" value="IGNORE_MISSING_BLOBS" />
<param name="consistencyFix" value="false" />
<param name="consistencyCheck" value="false" />
</PersistenceManager>
<!-- Search index and the file system it uses. class: FQN of class implementing
the QueryHandler interface -->
<SearchIndex class="org.apache.jackrabbit.core.query.lucene.SearchIndex">
<param name="path" value="${wsp.home}/index" />
<param name="supportHighlighting" value="true" />
<param name="autoRepair" value="true" />
<param name="onWorkspaceInconsistency" value="log" />
<param name="indexingConfiguration" value="${rep.home}/indexing_configuration.xml" />
<param name="resultFetchSize" value="50" />
<param name="cacheSize" value="100000" />
<param name="enableConsistencyCheck" value="false" />
<param name="forceConsistencyCheck" value="false" />
</SearchIndex>
</Workspace>
<!-- Configures the versioning -->
<Versioning rootPath="${rep.home}/version">
<!-- Configures the filesystem to use for versioning for the respective
persistence manager -->
<FileSystem class="org.apache.jackrabbit.core.fs.local.LocalFileSystem">
<param name="path" value="${rep.home}/version" />
</FileSystem>
<PersistenceManager class="org.apache.jackrabbit.core.persistence.pool.PostgreSQLPersistenceManager">
<param name="driver" value="org.postgresql.Driver" />
<param name="url" value="jdbc:postgresql://postgres:5432/workspace-db" />
<param name="schema" value="postgresql" />
<param name="user" value="ws-db-user" />
<param name="password" value="dbPwd" />
<param name="schemaObjectPrefix" value="pm_version_" />
<param name="bundleCacheSize" value="600" />
<param name="consistencyFix" value="false" />
<param name="consistencyCheck" value="false" />
</PersistenceManager>
</Versioning>
<!-- Cluster configuration -->
<!-- Cluster id="storagehub1.d4science.org" syncDelay="2000">
<Journal class="org.apache.jackrabbit.core.journal.DatabaseJournal">
<param name="driver" value="org.postgresql.Driver" />
<param name="url" value="jdbc:postgresql://postgres/workspace-db" />
<param name="databaseType" value="postgresql" />
<param name="schemaObjectPrefix" value="journal_" />
<param name="user" value="ws-db-user" />
<param name="password" value="dbPwd" />
<param name="revision" value="${rep.home}/revision.log" />
<param name="janitorEnabled" value="false"/>
<set to true if you want to daily clean the journal table https://wiki.apache.org/jackrabbit/Clustering#Removing_Old_Revisions>
</Journal>
</Cluster > -->
</Repository>

View File

@ -0,0 +1,23 @@
[node]
mode = offline
hostname = dlib29.isti.cnr.it
protocol= http
port = 8080
infrastructure = gcube
authorizeChildrenContext = true
publicationFrequencyInSeconds = 60
[properties]
SmartGearsDistribution = 4.0.0-SNAPSHOT
SmartGearsDistributionBundle = UnBundled
[site]
country = it
location = pisa
[authorization]
factory = org.gcube.smartgears.security.defaults.DefaultAuthorizationProviderFactory
factory.endpoint = https://accounts.dev.d4science.org/auth/realms/d4science/protocol/openid-connect/token
credentials.class = org.gcube.smartgears.security.SimpleCredentials
credentials.clientID = node-whn-test-uno-d-d4s.d4science.org
credentials.secret = 979bd3bc-5cc4-11ec-bf63-0242ac130002

View File

@ -0,0 +1,10 @@
default.bucketName = storagehub-dev
default.key = SHUBTEST
default.secret = wJalrXUtnFEMI/K7MDENG/bPxRfiCY
default.url = minio:9000
default.createBucket = true
volatile.bucketName = storagehub-volatile-dev
volatile.key = SHUBTEST
volatile.secret = wJalrXUtnFEMI/K7MDENG/bPxRfiCY
volatile.url = minio:9000
volatile.createBucket = true

25
docker/logback.xml Normal file
View File

@ -0,0 +1,25 @@
<configuration scan="true" debug="true">
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>Ï
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<logger name="org.gcube" level="DEBUG" />
<logger name="org.gcube.smartgears" level="TRACE" />
<logger name="org.gcube.smartgears.handlers" level="TRACE"/>
<logger name="org.gcube.common.events" level="WARN" />
<logger name="org.gcube.data.publishing" level="ERROR" />
<logger name="org.gcube.documentstore" level="ERROR" />
<logger name="org.gcube.common.core.publisher.is.legacy" level="TRACE" />
<logger name="org.gcube.data.access" level="TRACE" />
<logger name="org.gcube.data.access.storagehub.handlers" level="DEBUG"/>
<root level="WARN">
<appender-ref ref="STDOUT" />
</root>
</configuration>

6
docker/properties Normal file
View File

@ -0,0 +1,6 @@
${{adminId}}=workspace
${{adminPwd}}=gcube
${{db-host}}=postgres
${{ws-db}}=workspace-db
${{dbUser}}=ws-db-user
${{dbPwd}}=dbPwd

View File

@ -0,0 +1,10 @@
default.bucketName=storagehub-dev
default.key=SHUBTEST
default.secret=wJalrXUtnFEMI/K7MDENG/bPxRfiCY
default.url=http://minio:9000/
default.createBucket=true
volatile.bucketName=storagehub-volatile-dev
volatile.key=SHUBTEST
volatile.secret=wJalrXUtnFEMI/K7MDENG/bPxRfiCY
volatile.url=http://minio:9000/
volatile.createBucket=true

10
docker/storagehub.xml Normal file
View File

@ -0,0 +1,10 @@
<Context path="/storagehub">
<Resource
name="jcr/repository"
auth="Container"
type="javax.jcr.Repository"
factory="org.apache.jackrabbit.core.jndi.BindableRepositoryFactory"
configFilePath="/app/jackrabbit/repository.xml"
repHomeDir="/app/jackrabbit/workspaces"
/>
</Context>

24
enunciate.xml Normal file
View File

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<enunciate
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://enunciate.webcohesion.com/schemas/enunciate-2.14.0.xsd">
<api-classes>
<!-- Use patterns to exclude classes... e.g. for URI-Resolver <exclude
pattern="org.gcube.datatransfer.resolver.services.DocsGenerator" /> -->
</api-classes>
<modules>
<gwt-json-overlay disabled="true" />
<php-json-client disabled="true" />
<ruby-json-client disabled="true" />
<java-json-client disabled="true" />
<javascript-client disabled="true" />
<docs docsDir="${project.build.directory}" docsSubdir="api-docs" />
<docs
freemarkerTemplate="${project.basedir}/src/main/resources/META-INF/enunciate/d4science_docs.fmt">
<additional-css
file="css/d4science_enunciate_custom.css" />
</docs>
<swagger basePath="/workspace" />
</modules>
</enunciate>

View File

@ -0,0 +1,6 @@
name: StorageHub
group: DataAccess
version: ${version}
description: ${description}
excludes:
- path: /workspace/api-docs/*

View File

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright (c) 2013, 2022 Oracle and/or its affiliates. All rights reserved.
This program and the accompanying materials are made available under the
terms of the Eclipse Distribution License v. 1.0, which is available at
http://www.eclipse.org/org/documents/edl-v10.php.
SPDX-License-Identifier: BSD-3-Clause
-->
<beans xmlns="https://jakarta.ee/xml/ns/jakartaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/beans_4_0.xsd"
version="4.0" bean-discovery-mode="all">
</beans>

View File

@ -2,11 +2,11 @@
<web-app>
<context-param>
<param-name>admin-username</param-name>
<param-value>workspacerep.imarine</param-value>
<param-value>admin</param-value>
</context-param>
<context-param>
<param-name>admin-pwd</param-name>
<param-value>gcube2010*onan</param-value>
<param-value>admin</param-value>
</context-param>
<context-param>
<param-name>resolver-basepath</param-name>

417
pom.xml
View File

@ -1,143 +1,120 @@
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>maven-parent</artifactId>
<groupId>org.gcube.tools</groupId>
<version>1.1.0</version>
<relativePath />
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>org.gcube.data.access</groupId>
<artifactId>storagehub</artifactId>
<version>1.4.0</version>
<version>1.5.0-SNAPSHOT</version>
<name>storagehub</name>
<scm>
<connection>scm:git:https://code-repo.d4science.org/gCubeSystem/storagehub.git</connection>
<developerConnection>scm:git:https://code-repo.d4science.org/gCubeSystem/storagehub.git</developerConnection>
<connection>
scm:git:https://code-repo.d4science.org/gCubeSystem/storagehub.git</connection>
<developerConnection>
scm:git:https://code-repo.d4science.org/gCubeSystem/storagehub.git</developerConnection>
<url>https://code-repo.d4science.org/gCubeSystem/storagehub</url>
</scm>
<packaging>war</packaging>
<properties>
<webappDirectory>${project.basedir}/src/main/webapp/WEB-INF</webappDirectory>
<jackrabbit.version>2.20.2</jackrabbit.version>
<jackson.version>2.8.11</jackson.version>
<slf4j.version>1.7.4</slf4j.version>
<tomcat.version>7.0.40</tomcat.version>
<jetty.version>6.1.26</jetty.version>
<tika.version>1.21</tika.version>
<jackrabbit.version>2.20.7</jackrabbit.version>
<jackson.version>2.15.3</jackson.version>
<slf4j.version>2.0.12</slf4j.version>
<tika.version>2.6.0</tika.version>
<aspectj-plugin.version>1.15.0</aspectj-plugin.version>
<distroDirectory>${project.basedir}/distro</distroDirectory>
<description>REST web service for Jackrabbit</description>
<warname>storagehub</warname>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<enunciate.version>2.17.1</enunciate.version>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.gcube.distribution</groupId>
<artifactId>gcube-smartgears-bom</artifactId>
<version>2.0.0</version>
<version>3.0.1-SNAPSHOT</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.8.2</version>
</dependency>
</dependencies>
<!-- https://mvnrepository.com/artifact/org.apache.tika/tika-parsers -->
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
</dependency>
<dependency>
<groupId>org.gcube.core</groupId>
<artifactId>common-smartgears</artifactId>
</dependency>
<dependency>
<groupId>org.gcube.core</groupId>
<artifactId>common-smartgears-app</artifactId>
</dependency>
<dependency>
<groupId>org.gcube.common</groupId>
<artifactId>authorization-control-library</artifactId>
<version>[1.0.0,2.0.0-SNAPSHOT)</version>
</dependency>
<dependency>
<groupId>org.gcube.common</groupId>
<artifactId>common-authorization</artifactId>
</dependency>
<dependency>
<groupId>org.gcube.core</groupId>
<artifactId>common-encryption</artifactId>
</dependency>
<dependency>
<groupId>org.gcube.core</groupId>
<artifactId>common-scope-maps</artifactId>
</dependency>
<dependency>
<groupId>org.gcube.core</groupId>
<artifactId>common-scope</artifactId>
</dependency>
<dependency>
<groupId>org.gcube.common</groupId>
<artifactId>storagehub-model</artifactId>
<version>[1.0.0,2.0.0-SNAPSHOT)</version>
</dependency>
<dependency>
<groupId>org.gcube.data.access</groupId>
<artifactId>storagehub-script-utils</artifactId>
<version>[1.0.0-SNAPSHOT,2.0.0)</version>
<version>[2.0.0-SNAPSHOT,3.0.0)</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itextpdf</artifactId>
<version>5.5.13.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.bouncycastle/bcprov-jdk15on -->
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<version>1.62</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
<dependency>
<groupId>org.gcube.common</groupId>
<artifactId>gxJRS</artifactId>
</dependency>
<!-- JCR dependencies -->
<dependency>
<groupId>javax.jcr</groupId>
<artifactId>jcr</artifactId>
@ -153,79 +130,72 @@
<artifactId>jackrabbit-core</artifactId>
<version>${jackrabbit.version}</version>
</dependency>
<dependency>
<groupId>org.apache.jackrabbit</groupId>
<artifactId>jackrabbit-jcr-server</artifactId>
<version>${jackrabbit.version}</version>
</dependency>
<!-- <dependency> <groupId>org.apache.jackrabbit</groupId>
<artifactId>jackrabbit-jcr-server</artifactId>
<version>${jackrabbit.version}</version> </dependency> -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>${jackson.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>${jackson.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${jackson.version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.tika/tika-parsers -->
<dependency>
<groupId>org.apache.tika</groupId>
<artifactId>tika-parsers</artifactId>
<version>1.21</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.tika/tika-core -->
<dependency>
<groupId>org.apache.tika</groupId>
<artifactId>tika-core</artifactId>
<version>1.21</version>
<version>${tika.version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/net.bull.javamelody/javamelody-core -->
<dependency>
<groupId>net.bull.javamelody</groupId>
<artifactId>javamelody-core</artifactId>
<version>1.82.0</version>
<groupId>org.apache.tika</groupId>
<artifactId>tika-parsers-standard-package</artifactId>
<version>${tika.version}</version>
</dependency>
<!-- needed to manage strange image types -->
<dependency>
<groupId>com.twelvemonkeys.imageio</groupId>
<artifactId>imageio-jpeg</artifactId>
<version>3.3.2</version>
</dependency>
<dependency>
<groupId>com.twelvemonkeys.imageio</groupId>
<artifactId>imageio-bmp</artifactId>
<version>3.3.2</version>
</dependency>
<dependency>
<groupId>com.twelvemonkeys.imageio</groupId>
<artifactId>imageio-core</artifactId>
<version>3.3.2</version>
</dependency>
<!-- jersey & weld -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.0.1</version>
<groupId>jakarta.servlet</groupId>
<artifactId>jakarta.servlet-api</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/javax.interceptor/javax.interceptor-api -->
<!--
https://mvnrepository.com/artifact/javax.interceptor/javax.interceptor-api -->
<dependency>
<groupId>javax.interceptor</groupId>
<artifactId>javax.interceptor-api</artifactId>
<version>1.2.2</version>
<groupId>jakarta.interceptor</groupId>
<artifactId>jakarta.interceptor-api</artifactId>
<version>2.0.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/javax.enterprise/cdi-api -->
<dependency>
<groupId>javax.enterprise</groupId>
<artifactId>cdi-api</artifactId>
<version>2.0</version>
<groupId>jakarta.enterprise</groupId>
<artifactId>jakarta.enterprise.cdi-api</artifactId>
<version>4.0.1</version>
</dependency>
<dependency>
<groupId>javax.ws.rs</groupId>
<artifactId>javax.ws.rs-api</artifactId>
<groupId>jakarta.ws.rs</groupId>
<artifactId>jakarta.ws.rs-api</artifactId>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-servlet</artifactId>
@ -234,14 +204,12 @@
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-servlet-core</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/org.glassfish.jersey.inject/jersey-hk2 -->
<!--
https://mvnrepository.com/artifact/org.glassfish.jersey.inject/jersey-hk2 -->
<dependency>
<groupId>org.glassfish.jersey.inject</groupId>
<artifactId>jersey-hk2</artifactId>
<version>2.30.1</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.core</groupId>
<artifactId>jersey-server</artifactId>
@ -254,92 +222,57 @@
<groupId>org.glassfish.jersey.ext.cdi</groupId>
<artifactId>jersey-cdi1x-servlet</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/org.jboss.weld.se/weld-se-core -->
<dependency>
<groupId>org.jboss.weld.servlet</groupId>
<artifactId>weld-servlet-core</artifactId>
<version>3.1.0.Final</version>
<groupId>org.jboss.weld.se</groupId>
<artifactId>weld-se-core</artifactId>
<version>5.1.2.Final</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.jboss/jandex -->
<dependency>
<groupId>org.jboss</groupId>
<artifactId>jandex</artifactId>
<version>2.2.2.Final</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.0.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.glassfish.jersey.core/jersey-common -->
<!--
https://mvnrepository.com/artifact/org.glassfish.jersey.core/jersey-common -->
<dependency>
<groupId>org.glassfish.jersey.core</groupId>
<artifactId>jersey-common</artifactId>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-json-jackson</artifactId>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-multipart</artifactId>
</dependency>
<dependency>
<groupId>postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>9.1-901.jdbc4</version>
<scope>runtime</scope>
</dependency>
<!-- Storage dependencies -->
<dependency>
<groupId>org.gcube.contentmanagement</groupId>
<artifactId>storage-manager-core</artifactId>
<version>[3.0.0-SNAPSHOT,4.0.0-SNAPSHOT)</version>
</dependency>
<dependency>
<groupId>org.gcube.contentmanagement</groupId>
<artifactId>storage-manager-wrapper</artifactId>
<version>[3.0.0-SNAPSHOT,4.0.0-SNAPSHOT)</version>
</dependency>
<dependency>
<groupId>org.reflections</groupId>
<artifactId>reflections</artifactId>
<version>0.9.10</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.postgresql/postgresql -->
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>42.7.0</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>16.0</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-compress</artifactId>
<version>1.17</version>
<version>1.22</version>
</dependency>
<dependency>
<groupId>org.tukaani</groupId>
<artifactId>xz</artifactId>
<version>1.5</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.test-framework.providers</groupId>
<artifactId>jersey-test-framework-provider-simple</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.derby</groupId>
<artifactId>derby</artifactId>
@ -352,111 +285,112 @@
<version>10.8.2.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.googlecode.jeeunit</groupId>
<artifactId>jeeunit</artifactId>
<version>1.0.0</version>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/com.google.code.gson/gson -->
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.7</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.vlkan.rfos</groupId>
<artifactId>rotating-fos</artifactId>
<version>0.9.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.mockito/mockito-all -->
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-all</artifactId>
<version>1.9.5</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jul-to-slf4j</artifactId>
<version>${slf4j.version}</version>
</dependency>
<!--
https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-to-slf4j -->
<!-- https://mvnrepository.com/artifact/org.slf4j/log4j-over-slf4j -->
<dependency>
<groupId>org.jboss.weld.se</groupId>
<artifactId>weld-se</artifactId>
<version>2.2.10.Final</version>
<groupId>org.slf4j</groupId>
<artifactId>log4j-over-slf4j</artifactId>
<version>2.0.7</version>
</dependency>
<!-- enunciate deps -->
<dependency>
<groupId>com.webcohesion.enunciate</groupId>
<artifactId>enunciate-core-annotations</artifactId>
<version>${enunciate.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.webcohesion.enunciate</groupId>
<artifactId>enunciate-rt-util</artifactId>
<version>${enunciate.version}</version>
<scope>provided</scope>
</dependency>
<!-- Storage dependencies -->
<dependency>
<groupId>org.gcube.contentmanagement</groupId>
<artifactId>storage-manager-core</artifactId>
<version>[4.0.0-SNAPSHOT,5.0.0-SNAPSHOT)</version>
</dependency>
<dependency>
<groupId>org.gcube.contentmanagement</groupId>
<artifactId>storage-manager-wrapper</artifactId>
<version>[4.0.0-SNAPSHOT,5.0.0-SNAPSHOT)</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.amazonaws/aws-java-sdk-s3 -->
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-java-sdk-s3</artifactId>
<version>1.12.683</version>
</dependency>
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.3.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/io.minio/minio
<dependency>
<groupId>io.minio</groupId>
<artifactId>minio</artifactId>
<version>8.3.3</version>
</dependency> -->
<dependency>
<groupId>org.gcube.common</groupId>
<artifactId>storagehub-client-library</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>testcontainers</artifactId>
<version>1.16.3</version>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/junit/junit -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.test-framework</groupId>
<artifactId>jersey-test-framework-core</artifactId>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.test-framework.providers</groupId>
<artifactId>jersey-test-framework-provider-grizzly2</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<finalName>${project.artifactId}</finalName>
<resources>
<resource>
<directory>src/main/resources</directory>
</resource>
</resources>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.eclipse.m2e</groupId>
<artifactId>lifecycle-mapping</artifactId>
<version>1.0.0</version>
<configuration>
<lifecycleMappingMetadata>
<pluginExecutions>
<pluginExecution>
<pluginExecutionFilter>
<groupId>org.codehaus.mojo</groupId>
<artifactId>aspectj-maven-plugin</artifactId>
<versionRange>[1.0,)</versionRange>
<goals>
<goal>test-compile</goal>
<goal>compile</goal>
</goals>
</pluginExecutionFilter>
<action>
<execute />
</action>
</pluginExecution>
</pluginExecutions>
</lifecycleMappingMetadata>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>aspectj-maven-plugin</artifactId>
<version>1.7</version>
<version>${aspectj-plugin.version}</version>
<configuration>
<complianceLevel>1.8</complianceLevel>
<source>1.8</source>
<target>1.8</target>
<complianceLevel>17</complianceLevel>
<source>17</source>
<target>17</target>
<aspectLibraries>
<aspectLibrary>
<groupId>org.gcube.common</groupId>
@ -464,10 +398,18 @@
</aspectLibrary>
</aspectLibraries>
</configuration>
<dependencies>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjtools</artifactId>
<version>1.9.21.1</version>
</dependency>
</dependencies>
<executions>
<execution>
<goals>
<goal>compile</goal>
<goal>compile</goal> <!-- use this goal to weave
all your main classes -->
</goals>
</execution>
</executions>
@ -486,22 +428,41 @@
<failOnMissingWebXml>false</failOnMissingWebXml>
</configuration>
</plugin>
<!-- Enunciate Maven plugin -->
<plugin>
<groupId>com.webcohesion.enunciate</groupId>
<artifactId>enunciate-maven-plugin</artifactId>
<version>${enunciate.version}</version>
<configuration></configuration>
<executions>
<execution>
<id>assemble</id>
<goals>
<goal>assemble</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- Copy Enunciate Documentation from your-application/docs to
your-application.war -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>2.6</version>
<executions>
<execution>
<id>copy-profile</id>
<id>copy-enunciate-docs</id>
<phase>process-resources</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<phase>process-resources</phase>
<configuration>
<outputDirectory>${webappDirectory}</outputDirectory>
<outputDirectory>target</outputDirectory>
<resources>
<resource>
<directory>${distroDirectory}</directory>
<targetPath>
${project.build.directory}/${project.artifactId}/api-docs</targetPath>
<directory>
${project.build.directory}/api-docs</directory>
<filtering>true</filtering>
</resource>
</resources>
@ -511,5 +472,35 @@
</plugin>
</plugins>
</build>
<profiles>
<profile>
<id>integration</id>
<build>
<finalName>storagehub-test-storages</finalName>
<plugins>
<plugin>
<artifactId>maven-antrun-plugin</artifactId>
<version>1.7</version>
<executions>
<execution>
<phase>process-test-classes</phase>
<configuration>
<target>
<copy todir="${basedir}/target/classes">
<fileset
dir="${basedir}/target/test-classes"
includes="org/gcube/data/access/storages/**/*" />
</copy>
</target>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
</project>

View File

@ -2,8 +2,8 @@ package org.gcube.data.access.storagehub;
import java.util.List;
import javax.inject.Inject;
import javax.inject.Singleton;
import jakarta.inject.Inject;
import jakarta.inject.Singleton;
import javax.jcr.Node;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
@ -49,7 +49,7 @@ public class AuthorizationChecker {
ACLManagerInterface aclManager;
public void checkReadAuthorizationControl(Session session, String userToCheck, String id) throws UserNotAuthorizedException , BackendGenericError, RepositoryException{
Node node = session.getNodeByIdentifier(id);
Item item = node2Item.getItem(node, Excludes.ALL);
@ -103,13 +103,13 @@ public class AuthorizationChecker {
private boolean hasParentPublicFolder(Session session, Item item) {
if(item==null || item.getParentPath()==null) return false;
if (item.getParentPath().replaceAll("/Home/[^/]*/"+Constants.WORKSPACE_ROOT_FOLDER_NAME,"").isEmpty() || item.getParentPath().replaceAll(Constants.SHARED_FOLDER_PATH, "").isEmpty()) {
if (item instanceof FolderItem)
return ((FolderItem) item).isPublicItem();
if (item instanceof FolderItem folder)
return folder.isPublicItem();
else return false;
} else {
if (item instanceof FolderItem)
if (item instanceof FolderItem folder)
try {
return ((FolderItem) item).isPublicItem() || hasParentPublicFolder(session, node2Item.getItem(item.getParentId(), session, Excludes.ALL));
return (folder.isPublicItem() || hasParentPublicFolder(session, node2Item.getItem(folder.getParentId(), session, Excludes.ALL)));
}catch (Throwable e) {
log.warn("error checking public parents",e);
return false;

View File

@ -3,6 +3,8 @@ package org.gcube.data.access.storagehub;
import java.util.Arrays;
import java.util.List;
import javax.jcr.SimpleCredentials;
public class Constants {
public static final String OLD_VRE_FOLDER_PARENT_NAME = "MySpecialFolders";
@ -17,6 +19,8 @@ public class Constants {
public static final String SHARED_WITH_ME_PARENT_NAME = "SharedWithMe";
//public static final String MYSHARED_PARENT_NAME = "MyShared";
public static final String SHARED_FOLDER_PATH = "/Share";
public static final String WORKSPACE_ROOT_FOLDER_NAME ="Workspace";
@ -25,10 +29,6 @@ public class Constants {
public static final String QUERY_LANGUAGE ="JCR-SQL2";
public static final String ADMIN_PARAM_NAME ="admin-username";
public static final String ADMIN_PARAM_PWD ="admin-pwd";
public static final String HOME_VERSION_PROP = "hl:version";
public static final List<String> FOLDERS_TO_EXLUDE = Arrays.asList(Constants.OLD_VRE_FOLDER_PARENT_NAME, Constants.TRASH_ROOT_FOLDER_NAME);
@ -36,4 +36,8 @@ public class Constants {
public static final List<String> WRITE_PROTECTED_FOLDER = Arrays.asList(Constants.OLD_VRE_FOLDER_PARENT_NAME, Constants.TRASH_ROOT_FOLDER_NAME);
public static final List<String> PROTECTED_FOLDER = Arrays.asList(Constants.WORKSPACE_ROOT_FOLDER_NAME, Constants.OLD_VRE_FOLDER_PARENT_NAME, Constants.TRASH_ROOT_FOLDER_NAME);
public static final String ADMIN_USER ="admin";
public static final SimpleCredentials JCR_CREDENTIALS = new SimpleCredentials(ADMIN_USER,"admin".toCharArray());
}

View File

@ -1,141 +0,0 @@
package org.gcube.data.access.storagehub;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class MultipleOutputStream {
private Logger logger = LoggerFactory.getLogger(MultipleOutputStream.class);
private MyPipedInputStream[] pipedInStreams;
private InputStream is;
private MyPipedOututStream[] pipedOutStreams;
private int index=0;
public MultipleOutputStream(InputStream is, int number) throws IOException{
this.is = is;
logger.debug("requested {} piped streams ",number);
pipedInStreams = new MyPipedInputStream[number];
pipedOutStreams = new MyPipedOututStream[number];
for (int i =0; i<number; i++) {
pipedOutStreams[i] = new MyPipedOututStream();
pipedInStreams[i] = new MyPipedInputStream(pipedOutStreams[i]);
}
}
public void startWriting() throws IOException{
BufferedInputStream bis = new BufferedInputStream(is);
byte[] buf = new byte[1024*64];
int read=-1;
int writeTot = 0;
while ((read =bis.read(buf))!=-1){
for (int i=0; i< pipedInStreams.length; i++) {
if (!pipedInStreams[i].isClosed()) {
pipedOutStreams[i].write(buf, 0, read);
}
}
writeTot+= read;
if (allOutStreamClosed())
break;
}
for (int i=0; i< pipedOutStreams.length; i++) {
if (!pipedOutStreams[i].isClosed()) {
logger.debug("closing outputstream {}",i);
pipedOutStreams[i].close();
}
}
logger.debug("total written {} ",writeTot);
}
private boolean allOutStreamClosed() {
for (int i=0; i<pipedOutStreams.length; i++) {
if (!pipedOutStreams[i].isClosed())
return false;
}
return true;
}
public synchronized InputStream get() {
logger.debug("requesting piped streams {}",index);
if (index>=pipedInStreams.length) return null;
return pipedInStreams[index++];
}
public class MyPipedOututStream extends PipedOutputStream{
boolean close = false;
@Override
public void close() throws IOException {
this.close = true;
super.close();
}
/**
* @return the close
*/
public boolean isClosed() {
return close;
}
@Override
public void write(byte[] b, int off, int len) throws IOException {
try{
super.write(b, off, len);
}catch(IOException io){
this.close = true;
}
}
}
public class MyPipedInputStream extends PipedInputStream{
boolean close = false;
public MyPipedInputStream(PipedOutputStream src) throws IOException {
super(src);
}
@Override
public void close() throws IOException {
this.close = true;
logger.debug(Thread.currentThread().getName()+" close MyPipedInputStream");
super.close();
}
/**
* @return the close
*/
public boolean isClosed() {
return close;
}
}
}

View File

@ -1,10 +1,6 @@
package org.gcube.data.access.storagehub;
import javax.inject.Inject;
import javax.ws.rs.ext.Provider;
import org.apache.jackrabbit.api.JackrabbitRepository;
import org.gcube.data.access.storagehub.services.RepositoryInitializer;
import org.gcube.data.access.storagehub.repository.StoragehubRepository;
import org.glassfish.jersey.server.monitoring.ApplicationEvent;
import org.glassfish.jersey.server.monitoring.ApplicationEventListener;
import org.glassfish.jersey.server.monitoring.RequestEvent;
@ -12,21 +8,21 @@ import org.glassfish.jersey.server.monitoring.RequestEventListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import jakarta.ws.rs.ext.Provider;
@Provider
public class MyApplicationListener implements ApplicationEventListener {
private static final Logger log = LoggerFactory.getLogger(MyApplicationListener.class);
@Inject
RepositoryInitializer repository;
StoragehubRepository repository = StoragehubRepository.repository;
@Override
public void onEvent(ApplicationEvent event) {
log.info("StorageHub - event called");
switch (event.getType()) {
case DESTROY_FINISHED:
log.info("Destroying application storageHub");
((JackrabbitRepository) repository.getRepository()).shutdown();
repository.shutdown();
log.info("Jackrabbit repository stopped");
default:
break;

View File

@ -1,6 +1,6 @@
package org.gcube.data.access.storagehub;
import javax.inject.Singleton;
import jakarta.inject.Singleton;
import javax.jcr.Node;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
@ -46,8 +46,13 @@ public class PathUtil {
}
public Path getSharedWithMePath(String login){
return Paths.append(getWorkspacePath(login),Constants.SHARED_WITH_ME_PARENT_NAME);
return Paths.append(getHome(login),Constants.SHARED_WITH_ME_PARENT_NAME);
}
/*
public Path getMySharedPath(String login){
return Paths.append(getHome(login),Constants.MYSHARED_PARENT_NAME);
}*/
public Path getVREsPath(String login, Session session) throws RepositoryException {
Path home = getHome(login);

View File

@ -1,35 +0,0 @@
package org.gcube.data.access.storagehub;
import javax.inject.Singleton;
import javax.jcr.Repository;
import javax.naming.Context;
import javax.naming.InitialContext;
import org.apache.jackrabbit.api.JackrabbitRepository;
import org.gcube.data.access.storagehub.services.RepositoryInitializer;
@Singleton
public class RepositoryInitializerImpl implements RepositoryInitializer{
private Repository repository;
@Override
public synchronized Repository getRepository(){
return repository;
}
protected RepositoryInitializerImpl() throws Exception{
InitialContext context = new InitialContext();
Context environment = (Context) context.lookup("java:comp/env");
repository = (Repository) environment.lookup("jcr/repository");
}
public void shutdown() {
((JackrabbitRepository)repository).shutdown();
}
}

View File

@ -4,8 +4,8 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.StreamingOutput;
import jakarta.ws.rs.WebApplicationException;
import jakarta.ws.rs.core.StreamingOutput;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

View File

@ -1,36 +0,0 @@
package org.gcube.data.access.storagehub;
import java.util.Map;
import java.util.WeakHashMap;
import org.gcube.common.authorization.library.provider.AuthorizationProvider;
import org.gcube.contentmanagement.blobstorage.service.IClient;
import org.gcube.contentmanager.storageclient.model.protocol.smp.Handler;
import org.gcube.contentmanager.storageclient.wrapper.AccessType;
import org.gcube.contentmanager.storageclient.wrapper.MemoryType;
import org.gcube.contentmanager.storageclient.wrapper.StorageClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class StorageFactory {
public final static String SERVICE_NAME = "home-library";
public final static String SERVICE_CLASS = "org.gcube.portlets.user";
private static Map<String, IClient> clientUserMap = new WeakHashMap<String, IClient>();
private static Logger log = LoggerFactory.getLogger(StorageFactory.class);
public static IClient getGcubeStorage(){
String login = AuthorizationProvider.instance.get().getClient().getId();
if (!clientUserMap.containsKey(login)){
IClient storage = new StorageClient(SERVICE_CLASS, SERVICE_NAME,
login, AccessType.SHARED, MemoryType.PERSISTENT).getClient();
log.info("******* Storage activateProtocol for Storage **********");
Handler.activateProtocol();
clientUserMap.put(login, storage);
return storage;
} else return clientUserMap.get(login);
}
}

View File

@ -3,17 +3,19 @@ package org.gcube.data.access.storagehub;
import java.util.HashSet;
import java.util.Set;
import javax.ws.rs.Path;
import javax.ws.rs.core.Application;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.core.Application;
import org.gcube.common.gxrest.response.entity.SerializableErrorEntityTextWriter;
import org.gcube.data.access.storagehub.services.ACLManager;
import org.gcube.data.access.storagehub.services.DocsGenerator;
import org.gcube.data.access.storagehub.services.GroupManager;
import org.gcube.data.access.storagehub.services.Impersonable;
import org.gcube.data.access.storagehub.services.ItemSharing;
import org.gcube.data.access.storagehub.services.ItemsCreator;
import org.gcube.data.access.storagehub.services.ItemsManager;
import org.gcube.data.access.storagehub.services.MessageManager;
import org.gcube.data.access.storagehub.services.StorageManager;
import org.gcube.data.access.storagehub.services.UserManager;
import org.gcube.data.access.storagehub.services.WorkspaceManager;
import org.gcube.data.access.storagehub.services.admin.ScriptManager;
@ -36,6 +38,8 @@ public class StorageHub extends Application {
classes.add(GroupManager.class);
classes.add(ScriptManager.class);
classes.add(MessageManager.class);
classes.add(StorageManager.class);
classes.add(DocsGenerator.class);
classes.add(MultiPartFeature.class);
classes.add(SerializableErrorEntityTextWriter.class);
classes.add(MyApplicationListener.class);

View File

@ -0,0 +1,98 @@
package org.gcube.data.access.storagehub;
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import org.apache.jackrabbit.api.JackrabbitSession;
import org.gcube.com.fasterxml.jackson.databind.ObjectMapper;
import org.gcube.common.storagehub.model.exporter.DumpData;
import org.gcube.data.access.storagehub.handlers.DataHandler;
import org.gcube.data.access.storagehub.repository.StoragehubRepository;
import org.gcube.smartgears.ApplicationManager;
import org.gcube.smartgears.ContextProvider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class StorageHubApplicationManager implements ApplicationManager {
private static Logger logger = LoggerFactory.getLogger(StorageHubApplicationManager.class);
private boolean alreadyShutDown = false;
private boolean alreadyInit = false;
private StoragehubRepository repository;
// private static NotificationClient notificationClient;
/*
* public static NotificationClient getNotificationClient() { return
* notificationClient; }
*/
public StorageHubApplicationManager() {
repository = StoragehubRepository.repository;
}
@Override
public synchronized void onInit() {
logger.info("onInit Called on storagehub");
try {
if (!alreadyInit) {
logger.info("jackrabbit initialization started");
repository.initContainerAtFirstStart();
DataHandler dh = new DataHandler();
Path shubSpecificConf = ContextProvider.get().appSpecificConfigurationFolder();
Path importPath = Paths.get(shubSpecificConf.toString(), "import");
Path mainFileImportPath = Paths.get(importPath.toString(), "data.json");
if (importPath.toFile().exists() && mainFileImportPath.toFile().exists()) {
Session session = null;
try {
ObjectMapper mapper = new ObjectMapper();
DumpData data = mapper.readValue(mainFileImportPath.toFile(), DumpData.class);
session = repository.getRepository().login();
dh.importData((JackrabbitSession) session, data);
session.save();
} catch (RepositoryException e) {
logger.error("error importing data", e);
} catch (IOException je) {
logger.error("error parsing json data, invalid schema file", je);
} finally {
if (session != null)
session.logout();
}
}
alreadyInit = true;
}
} catch (Throwable e) {
logger.error("unexpected error initiliazing storagehub", e);
}
}
@Override
public synchronized void onShutdown() {
if (!alreadyShutDown)
try {
logger.info("jackrabbit is shutting down");
repository.shutdown();
alreadyShutDown = true;
} catch (Exception e) {
logger.warn("the database was not shutdown properly", e);
}
}
}

View File

@ -1,41 +0,0 @@
package org.gcube.data.access.storagehub;
import org.gcube.data.access.storagehub.services.RepositoryInitializer;
import org.gcube.smartgears.ApplicationManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class StorageHubAppllicationManager implements ApplicationManager {
private static Logger logger = LoggerFactory.getLogger(StorageHubAppllicationManager.class);
private boolean alreadyShutDown = false;
public static RepositoryInitializer repository;
@Override
public synchronized void onInit() {
logger.info("jackrabbit initialization started");
try {
repository = new RepositoryInitializerImpl();
} catch (Exception e) {
logger.error("ERROR INITIALIZING REPOSITORY",e);
}
repository.getRepository();
}
@Override
public synchronized void onShutdown() {
if (!alreadyShutDown)
try {
logger.info("jackrabbit is shutting down");
repository.shutdown();
alreadyShutDown= true;
} catch (Exception e) {
logger.warn("the database was not shutdown properly",e);
}
}
}

View File

@ -30,18 +30,21 @@ import org.gcube.common.storagehub.model.exceptions.IdNotFoundException;
import org.gcube.common.storagehub.model.exceptions.ItemLockedException;
import org.gcube.common.storagehub.model.exceptions.StorageHubException;
import org.gcube.common.storagehub.model.exceptions.UserNotAuthorizedException;
import org.gcube.common.storagehub.model.items.AbstractFileItem;
import org.gcube.common.storagehub.model.items.ExternalLink;
import org.gcube.common.storagehub.model.items.FolderItem;
import org.gcube.common.storagehub.model.items.GCubeItem;
import org.gcube.common.storagehub.model.items.Item;
import org.gcube.common.storagehub.model.items.RootItem;
import org.gcube.common.storagehub.model.items.SharedFolder;
import org.gcube.common.storagehub.model.storages.MetaInfo;
import org.gcube.common.storagehub.model.types.ItemAction;
import org.gcube.common.storagehub.model.types.NodeProperty;
import org.gcube.data.access.storagehub.accounting.AccountingHandler;
import org.gcube.data.access.storagehub.handlers.items.Item2NodeConverter;
import org.gcube.data.access.storagehub.handlers.items.Node2ItemConverter;
import org.gcube.data.access.storagehub.handlers.items.builders.FolderCreationParameters;
import org.gcube.data.access.storagehub.handlers.plugins.StorageBackendHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -129,6 +132,7 @@ public class Utils {
}
public static <T extends Item> List<T> getItemList(Node parent, List<String> excludes, Range range, boolean showHidden, Class<? extends RootItem> nodeTypeToInclude) throws RepositoryException, BackendGenericError{
return getItemList(null, parent, excludes, range, showHidden, nodeTypeToInclude);
}
@ -188,7 +192,7 @@ public class Utils {
}
public static void copyStream(InputStream in, OutputStream out) throws IOException {
byte[] buffer = new byte[2048];
@ -211,19 +215,20 @@ public class Utils {
return false;
}
public static String checkExistanceAndGetUniqueName(Session ses, Node destination, String name) throws BackendGenericError{
String escapedName = Text.escapeIllegalJcrChars(name);
try {
destination.getNode(name);
destination.getNode(escapedName);
}catch(PathNotFoundException pnf) {
return Text.escapeIllegalJcrChars(name);
return escapedName;
} catch (Exception e) {
throw new BackendGenericError(e);
}
try {
String filename = FilenameUtils.getBaseName(name);
String ext = FilenameUtils.getExtension(name);
String filename = FilenameUtils.getBaseName(escapedName);
String ext = FilenameUtils.getExtension(escapedName);
String nameTocheck = ext.isEmpty()? String.format("%s(*)",filename): String.format("%s(*).%s",filename, ext);
@ -240,19 +245,21 @@ public class Utils {
String newName = ext.isEmpty()? String.format("%s(%d)", filename,maxval+1) : String.format("%s(%d).%s", filename,maxval+1, ext) ;
return Text.escapeIllegalJcrChars(newName);
return newName;
} catch (Exception e) {
throw new BackendGenericError(e);
}
}
public static Node createFolderInternally(FolderCreationParameters params, AccountingHandler accountingHandler) throws StorageHubException {
public static Node createFolderInternally(FolderCreationParameters params, AccountingHandler accountingHandler, boolean isInternalWSFolder) throws StorageHubException {
logger.debug("creating folder {} in {}", params.getName(), params.getParentId());
Node destinationNode;
FolderItem destinationItem;
try {
destinationNode = params.getSession().getNodeByIdentifier(params.getParentId());
destinationItem = (FolderItem) new Node2ItemConverter().getItem(destinationNode, Excludes.ALL);
}catch (RepositoryException e) {
throw new IdNotFoundException(params.getParentId());
}
@ -263,6 +270,20 @@ public class Utils {
item.setName(uniqueName);
item.setTitle(uniqueName);
item.setDescription(params.getDescription());
if (isInternalWSFolder) {
item.setBackend(StorageBackendHandler.getDefaultPayloadForFolder());
} else {
if (params.getBackend() != null)
item.setBackend(params.getBackend());
else {
if (destinationItem.getBackend() != null)
item.setBackend(destinationItem.getBackend());
else
item.setBackend(StorageBackendHandler.getDefaultPayloadForFolder());
}
}
//TODO: item.setExternalStorage();
//item.setCreationTime(now);
@ -346,5 +367,11 @@ public class Utils {
node.setProperty(NodeProperty.LAST_ACTION.toString(), action.name());
}
public static void setContentFromMetaInfo(AbstractFileItem item, MetaInfo contentInfo) {
item.getContent().setSize(contentInfo.getSize());
item.getContent().setRemotePath(contentInfo.getRemotePath());
item.getContent().setSize(contentInfo.getSize());
item.getContent().setPayloadBackend(contentInfo.getPayloadBackend());
}
}

View File

@ -4,21 +4,17 @@ import java.util.Calendar;
import java.util.Set;
import java.util.UUID;
import javax.inject.Singleton;
import javax.jcr.Node;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.jcr.UnsupportedRepositoryOperationException;
import javax.jcr.version.Version;
import javax.jcr.version.VersionHistory;
import javax.jcr.version.VersionIterator;
import javax.jcr.version.VersionManager;
import org.gcube.common.storagehub.model.items.nodes.accounting.AccountingEntryType;
import org.gcube.common.storagehub.model.types.NodeProperty;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import jakarta.inject.Singleton;
@Singleton
public class AccountingHandler {
@ -32,11 +28,12 @@ public class AccountingHandler {
private static final String OLD_ITEM_NAME = "hl:oldItemName";
private static final String NEW_ITEM_NAME = "hl:newItemName";
private static final String BASE_VERSION ="1.0";
private static final Logger logger = LoggerFactory.getLogger(AccountingHandler.class);
public void createReadObj(String title, Session ses, Node node, String login, boolean saveHistory ) {
public void createReadObj(String title, String version, Session ses, Node node, String login, boolean saveHistory ) {
try {
if (!node.hasNode(NodeProperty.ACCOUNTING.toString())){
@ -49,20 +46,8 @@ public class AccountingHandler {
accountingNode.setProperty(USER, login);
accountingNode.setProperty(DATE, Calendar.getInstance());
accountingNode.setProperty(ITEM_NAME, title);
try {
VersionManager vManager = ses.getWorkspace().getVersionManager();
VersionHistory history = vManager.getVersionHistory(node.getNode("jcr:content").getPath());
VersionIterator versions = history.getAllVersions();
Version version= null;
while (versions.hasNext()) {
version = versions.nextVersion();
}
if (version!=null)
accountingNode.setProperty(VERSION_ACCOUNTING, version.getName());
}catch(UnsupportedRepositoryOperationException uropex) {
logger.warn("version cannot be retrieved", uropex);
}
accountingNode.setProperty(VERSION_ACCOUNTING, version!=null?version:BASE_VERSION);
if (saveHistory) ses.save();
} catch (RepositoryException e) {
logger.warn("error trying to retrieve accountign node",e);
@ -81,6 +66,8 @@ public class AccountingHandler {
accountingNode.setProperty(USER, login);
accountingNode.setProperty(DATE, Calendar.getInstance());
accountingNode.setProperty(ITEM_NAME, title);
accountingNode.setProperty(VERSION_ACCOUNTING, BASE_VERSION);
if (saveHistory) ses.save();
} catch (RepositoryException e) {
@ -88,7 +75,7 @@ public class AccountingHandler {
}
}
public void createFileUpdated(String title, Session ses, Node node, String login, boolean saveHistory ) {
public void createFileUpdated(String title, String version, Session ses, Node node, String login, boolean saveHistory ) {
try {
if (!node.hasNode(NodeProperty.ACCOUNTING.toString())){
@ -97,25 +84,34 @@ public class AccountingHandler {
Node accountingNodeParent = node.getNode(NodeProperty.ACCOUNTING.toString());
Node accountingNode = accountingNodeParent.addNode(UUID.randomUUID().toString(),AccountingEntryType.UPDATE.getNodeTypeDefinition());
accountingNode.setProperty(USER, login);
accountingNode.setProperty(DATE, Calendar.getInstance());
accountingNode.setProperty(ITEM_NAME, title);
accountingNode.setProperty(VERSION_ACCOUNTING, version);
if (saveHistory) ses.save();
} catch (RepositoryException e) {
logger.warn("error trying to retrieve accountign node",e);
}
}
public void createVersionDeleted(String title, String version, Session ses, Node node, String login, boolean saveHistory ) {
try {
if (!node.hasNode(NodeProperty.ACCOUNTING.toString())){
node.addNode(NodeProperty.ACCOUNTING.toString(), NodeProperty.NT_ACCOUNTING.toString());
}
Node accountingNodeParent = node.getNode(NodeProperty.ACCOUNTING.toString());
Node accountingNode = accountingNodeParent.addNode(UUID.randomUUID().toString(),AccountingEntryType.DELETE.getNodeTypeDefinition());
accountingNode.setProperty(USER, login);
accountingNode.setProperty(DATE, Calendar.getInstance());
accountingNode.setProperty(ITEM_NAME, title);
try {
VersionManager vManager = ses.getWorkspace().getVersionManager();
VersionHistory history = vManager.getVersionHistory(node.getNode("jcr:content").getPath());
VersionIterator versions = history.getAllVersions();
Version version= null;
while (versions.hasNext()) {
version = versions.nextVersion();
}
if (version!=null)
accountingNode.setProperty(VERSION_ACCOUNTING, version.getName());
}catch(UnsupportedRepositoryOperationException uropex) {
logger.warn("version cannot be retrieved", uropex);
}
accountingNode.setProperty(VERSION_ACCOUNTING, version);
if (saveHistory) ses.save();

View File

@ -1,16 +0,0 @@
package org.gcube.data.access.storagehub.exception;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Response.Status;
public class MyAuthException extends WebApplicationException {
/**
*
*/
private static final long serialVersionUID = 1L;
public MyAuthException(Throwable cause) {
super(cause, Status.FORBIDDEN);
}
}

View File

@ -0,0 +1,5 @@
package org.gcube.data.access.storagehub.handlers;
public class ACLHandler {
}

View File

@ -40,11 +40,12 @@ public class ClassHandler {
Set<Class<?>> classesAnnotated = reflection.getTypesAnnotatedWith(RootNode.class);
for (Class<?> clazz: classesAnnotated ){
if (RootItem.class.isAssignableFrom(clazz)) {
String value = clazz.getAnnotation(RootNode.class).value();
log.debug("loading class {} with value {} ", clazz, value );
classMap.put(value, (Class<? extends RootItem>) clazz);
typeMap.put((Class<? extends RootItem>) clazz, value);
if (RootItem.class.isAssignableFrom(clazz) && clazz.isAnnotationPresent(RootNode.class)) {
String[] values = clazz.getAnnotation(RootNode.class).value();
log.debug("loading class {} with values {} ", clazz, values );
for (String value: values)
classMap.put(value, (Class<? extends RootItem>) clazz);
typeMap.put((Class<? extends RootItem>) clazz, values[0]);
}
}
}

View File

@ -8,21 +8,24 @@ import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
import javax.inject.Inject;
import jakarta.inject.Inject;
import javax.jcr.Node;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.jcr.version.Version;
import org.gcube.common.storagehub.model.Excludes;
import org.gcube.common.storagehub.model.Path;
import org.gcube.common.storagehub.model.Paths;
import org.gcube.common.storagehub.model.exceptions.BackendGenericError;
import org.gcube.common.storagehub.model.items.AbstractFileItem;
import org.gcube.common.storagehub.model.items.FolderItem;
import org.gcube.common.storagehub.model.items.Item;
import org.gcube.common.storagehub.model.plugins.FolderManager;
import org.gcube.common.storagehub.model.storages.StorageBackend;
import org.gcube.common.storagehub.model.storages.StorageBackendFactory;
import org.gcube.data.access.storagehub.Utils;
import org.gcube.data.access.storagehub.accounting.AccountingHandler;
import org.gcube.data.access.storagehub.handlers.plugins.FolderPluginHandler;
import org.gcube.data.access.storagehub.handlers.plugins.StorageBackendHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -31,9 +34,12 @@ public class CompressHandler {
private Logger logger = LoggerFactory.getLogger(CompressHandler.class);
@Inject
FolderPluginHandler pluginHandler;
StorageBackendHandler storageBackendHandler;
public Deque<Item> getAllNodesForZip(FolderItem directory, Session session, String login, AccountingHandler accountingHandler, List<String> excludes) throws RepositoryException, BackendGenericError{
@Inject
VersionHandler versionHandler;
public Deque<Item> getAllNodesForZip(FolderItem directory, String login, Session session, AccountingHandler accountingHandler, List<String> excludes) throws RepositoryException, BackendGenericError{
Deque<Item> queue = new LinkedList<Item>();
Node currentNode = session.getNodeByIdentifier(directory.getId());
queue.push(directory);
@ -42,11 +48,17 @@ public class CompressHandler {
for (Item item : Utils.getItemList(currentNode,Excludes.GET_ONLY_CONTENT, null, false, null)){
if (excludes.contains(item.getId())) continue;
if (item instanceof FolderItem)
tempQueue.addAll(getAllNodesForZip((FolderItem) item, session, login, accountingHandler, excludes));
else if (item instanceof AbstractFileItem){
tempQueue.addAll(getAllNodesForZip((FolderItem) item, login, session, accountingHandler, excludes));
else if (item instanceof AbstractFileItem fileItem){
logger.trace("adding file {}",item.getPath());
AbstractFileItem fileItem = (AbstractFileItem) item;
accountingHandler.createReadObj(fileItem.getTitle(), session, session.getNodeByIdentifier(item.getId()), login, false);
String versionName = null;
try {
Version version = versionHandler.getCurrentVersion((Node) item.getRelatedNode());
versionName = version.getName();
}catch(RepositoryException e) {
logger.warn("current version of {} cannot be retreived", item.getId());
}
accountingHandler.createReadObj(fileItem.getTitle(), versionName, session, (Node) item.getRelatedNode(), login, false);
queue.addLast(item);
}
}
@ -55,9 +67,9 @@ public class CompressHandler {
}
public void zipNode(ZipOutputStream zos, Deque<Item> queue, String login, org.gcube.common.storagehub.model.Path originalPath) throws Exception{
public void zipNode(ZipOutputStream zos, Deque<Item> queue, Path originalPath) throws Exception{
logger.trace("originalPath is {}",originalPath.toPath());
org.gcube.common.storagehub.model.Path actualPath = Paths.getPath("");
Path actualPath = Paths.getPath("");
while (!queue.isEmpty()) {
Item item = queue.pop();
if (item instanceof FolderItem) {
@ -71,11 +83,14 @@ public class CompressHandler {
}finally {
zos.closeEntry();
}
} else if (item instanceof AbstractFileItem){
} else if (item instanceof AbstractFileItem fileItem){
try {
AbstractFileItem fileItem = (AbstractFileItem)item;
FolderManager manager = pluginHandler.getFolderManager(fileItem);
InputStream streamToWrite = manager.getStorageBackend().download(fileItem.getContent());
StorageBackendFactory sbf = storageBackendHandler.get(fileItem.getContent().getPayloadBackend());
StorageBackend sb = sbf.create(fileItem.getContent().getPayloadBackend());
InputStream streamToWrite = sb.download(fileItem.getContent());
if (streamToWrite == null){
logger.warn("discarding item {} ",item.getName());
continue;

View File

@ -1,18 +0,0 @@
package org.gcube.data.access.storagehub.handlers;
import javax.jcr.SimpleCredentials;
import javax.servlet.ServletContext;
import org.gcube.data.access.storagehub.Constants;
public class CredentialHandler {
private static SimpleCredentials credentials;
public static SimpleCredentials getAdminCredentials(ServletContext context) {
if (credentials==null)
credentials = new SimpleCredentials(context.getInitParameter(Constants.ADMIN_PARAM_NAME),context.getInitParameter(Constants.ADMIN_PARAM_PWD).toCharArray());
return credentials;
}
}

View File

@ -0,0 +1,106 @@
package org.gcube.data.access.storagehub.handlers;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import javax.jcr.Node;
import javax.jcr.RepositoryException;
import org.apache.jackrabbit.api.JackrabbitSession;
import org.gcube.common.storagehub.model.acls.ACL;
import org.gcube.common.storagehub.model.acls.AccessType;
import org.gcube.common.storagehub.model.exceptions.StorageHubException;
import org.gcube.common.storagehub.model.exporter.DumpData;
import org.gcube.common.storagehub.model.exporter.GroupData;
import org.gcube.common.storagehub.model.exporter.UserData;
import org.gcube.common.storagehub.model.items.Item;
import org.gcube.data.access.storagehub.handlers.vres.VREManager;
import org.gcube.data.access.storagehub.services.delegates.ACLManagerDelegate;
import org.gcube.data.access.storagehub.services.delegates.GroupManagerDelegate;
import org.gcube.data.access.storagehub.services.delegates.UserManagerDelegate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import jakarta.inject.Inject;
import jakarta.inject.Singleton;
@Singleton
public class DataHandler {
public static final Logger logger = LoggerFactory.getLogger(DataHandler.class);
@Inject
UserManagerDelegate userHandler;
@Inject
GroupManagerDelegate groupHandler;
@Inject
ACLManagerDelegate aclHandler;
@Inject
VREManager vreManager;
public DumpData exportData(JackrabbitSession session) throws RepositoryException,StorageHubException {
DumpData data = new DumpData();
List<UserData> usersData = userHandler.getAllUsers(session).stream().map(u -> new UserData(u.getUserName()))
.collect(Collectors.toList());
data.setUsers(usersData);
List<String> groups = groupHandler.getGroups(session);
List<GroupData> groupsData = new ArrayList<GroupData>(groups.size());
for (String group : groups) {
Item vreFolderItem = vreManager.getVRE(group).getVreFolder();
String owner = vreFolderItem.getOwner();
List<ACL> acls = aclHandler.get(vreFolderItem, session);
AccessType accessType = AccessType.READ_ONLY;
List<ACL> otherAccess = new ArrayList<ACL>(acls.size() - 1);
for (ACL acl : acls)
if (acl.getPricipal().equals(group))
accessType = acl.getAccessTypes().get(0);
else
otherAccess.add(acl);
List<String> members = groupHandler.getUsersBelongingToGroup(session, group);
groupsData.add(new GroupData(group, owner, members, accessType, otherAccess));
}
data.setGroups(groupsData);
return data;
}
public void importData(JackrabbitSession session, DumpData data) {
data.getUsers().forEach(u -> {
try {
userHandler.createUser(session, u.getUserName(), "pwd");
} catch (RepositoryException | StorageHubException e) {
logger.warn("error importing user {} ", u.getUserName(), e);
}
});
data.getGroups().forEach(g -> {
try {
groupHandler.createGroup(session, g.getName(), g.getAccessType(), g.getFolderOwner(), true);
for (String member : g.getMembers())
try {
groupHandler.addUserToGroup(session, member, g.getName());
}catch(Throwable t ) {
logger.warn("error adding user {} to group {}", member, g.getName(), t);
}
Item vreFolderItem = vreManager.getVRE(g.getName()).getVreFolder();
for (ACL acl : g.getAcls()) {
aclHandler.update(acl.getPricipal(), (Node)vreFolderItem.getRelatedNode(), acl.getAccessTypes().get(0), session);
}
} catch (Throwable e) {
logger.warn("error importing group {} ", g.getName(), e);
}
});
}
}

View File

@ -0,0 +1,211 @@
package org.gcube.data.access.storagehub.handlers;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Deque;
import java.util.List;
import java.util.Map;
import java.util.zip.Deflater;
import java.util.zip.ZipOutputStream;
import jakarta.inject.Inject;
import jakarta.inject.Singleton;
import javax.jcr.Node;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.jcr.version.Version;
import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.core.StreamingOutput;
import org.apache.commons.io.FilenameUtils;
import org.gcube.common.storagehub.model.Constants;
import org.gcube.common.storagehub.model.Excludes;
import org.gcube.common.storagehub.model.Paths;
import org.gcube.common.storagehub.model.exceptions.InvalidItemException;
import org.gcube.common.storagehub.model.exceptions.PluginInitializationException;
import org.gcube.common.storagehub.model.exceptions.PluginNotFoundException;
import org.gcube.common.storagehub.model.exceptions.StorageHubException;
import org.gcube.common.storagehub.model.exceptions.StorageIdNotFoundException;
import org.gcube.common.storagehub.model.items.AbstractFileItem;
import org.gcube.common.storagehub.model.items.FolderItem;
import org.gcube.common.storagehub.model.items.Item;
import org.gcube.common.storagehub.model.items.nodes.Content;
import org.gcube.common.storagehub.model.items.nodes.PayloadBackend;
import org.gcube.common.storagehub.model.storages.StorageBackend;
import org.gcube.common.storagehub.model.storages.StorageBackendFactory;
import org.gcube.data.access.storagehub.SingleFileStreamingOutput;
import org.gcube.data.access.storagehub.accounting.AccountingHandler;
import org.gcube.data.access.storagehub.handlers.items.Node2ItemConverter;
import org.gcube.data.access.storagehub.handlers.plugins.StorageBackendHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@Singleton
public class DownloadHandler {
private static final Logger log = LoggerFactory.getLogger(DownloadHandler.class);
@Inject
private AccountingHandler accountingHandler;
@Inject
private StorageBackendHandler storageBackendHandler;
@Inject
private CompressHandler compressHandler;
@Inject
private VersionHandler versionHandler;
@Inject
private Node2ItemConverter node2Item;
public Response downloadFolderItem(Session ses, String login, FolderItem item, boolean withAccounting ) throws StorageHubException, RepositoryException {
try {
final Deque<Item> allNodes = compressHandler.getAllNodesForZip((FolderItem)item, login, ses, accountingHandler, Excludes.GET_ONLY_CONTENT);
final org.gcube.common.storagehub.model.Path originalPath = Paths.getPath(item.getParentPath());
StreamingOutput so = new StreamingOutput() {
@Override
public void write(OutputStream os) {
try(ZipOutputStream zos = new ZipOutputStream(os)){
long start = System.currentTimeMillis();
zos.setLevel(Deflater.BEST_COMPRESSION);
log.debug("writing StreamOutput");
compressHandler.zipNode(zos, allNodes, originalPath);
log.debug("StreamOutput written in {}",(System.currentTimeMillis()-start));
} catch (Exception e) {
log.error("error writing stream",e);
}
}
};
Response response = Response
.ok(so)
.header("content-disposition","attachment; filename = "+item.getTitle()+".zip")
.header("Content-Type", "application/zip")
.header("Content-Length", -1l)
.build();
if (withAccounting)
accountingHandler.createReadObj(item.getTitle(), null, ses, (Node) item.getRelatedNode(), login, false);
return response;
}finally {
if (ses!=null) ses.save();
}
}
public Response downloadFileItem(Session ses, AbstractFileItem fileItem, String login, boolean withAccounting) throws RepositoryException, PluginInitializationException, PluginNotFoundException, StorageHubException {
Content content = fileItem.getContent();
StorageBackendFactory sbf = storageBackendHandler.get(content.getPayloadBackend());
StorageBackend sb = sbf.create(content.getPayloadBackend());
InputStream streamToWrite = sb.download(content);
if (withAccounting) {
String versionName = null;
try {
Version version = versionHandler.getCurrentVersion((Node) fileItem.getRelatedNode());
versionName = version.getName();
}catch(RepositoryException e) {
log.warn("current version of {} cannot be retreived", fileItem.getId());
}
accountingHandler.createReadObj(fileItem.getTitle(), versionName, ses, (Node) fileItem.getRelatedNode(), login, true);
}
StreamingOutput so = new SingleFileStreamingOutput(streamToWrite);
return Response
.ok(so)
.header("content-disposition","attachment; filename = "+fileItem.getName())
.header("Content-Length", fileItem.getContent().getSize())
.header("Content-Type", fileItem.getContent().getMimeType())
.build();
}
public Response downloadVersionedItem(Session ses, String login, AbstractFileItem currentItem, String versionName, boolean withAccounting) throws RepositoryException, StorageHubException{
List<Version> jcrVersions = versionHandler.getContentVersionHistory((Node)currentItem.getRelatedNode());
for (Version version: jcrVersions) {
log.debug("retrieved version id {}, name {}", version.getIdentifier(), version.getName());
if (version.getName().equals(versionName)) {
Content content = node2Item.getContentFromVersion(version);
StorageBackendFactory sbf = storageBackendHandler.get(content.getPayloadBackend());
StorageBackend sb = sbf.create(content.getPayloadBackend());
InputStream streamToWrite = null;
try {
streamToWrite = sb.download(content);
}catch (StorageIdNotFoundException e) {
//TODO: temporary code, it will last until the MINIO porting will not finish
if (sbf.getName().equals(Constants.MONGO_STORAGE)) {
sbf = storageBackendHandler.get(Constants.DEFAULT_S3_STORAGE);
sbf.create(new PayloadBackend(Constants.DEFAULT_S3_STORAGE, null));
} else
throw e;
}
log.debug("retrieved storage id is {} with storageBackend {} (stream is null? {})",content.getStorageId(), sbf.getName(), streamToWrite==null );
String oldfilename = FilenameUtils.getBaseName(currentItem.getTitle());
String ext = FilenameUtils.getExtension(currentItem.getTitle());
String fileName = String.format("%s_v%s.%s", oldfilename, version.getName(), ext);
if (withAccounting)
accountingHandler.createReadObj(currentItem.getTitle(), versionName, ses, (Node) currentItem.getRelatedNode(), login, true);
StreamingOutput so = new SingleFileStreamingOutput(streamToWrite);
return Response
.ok(so)
.header("content-disposition","attachment; filename = "+fileName)
.header("Content-Length", content.getSize())
.header("Content-Type", content.getMimeType())
.build();
}
}
throw new InvalidItemException("the version is not valid");
}
public Response downloadFileFromStorageBackend(String storageId, String storageName) throws RepositoryException, PluginInitializationException, PluginNotFoundException, StorageHubException {
StorageBackendFactory sbf = storageBackendHandler.get(storageName);
StorageBackend sb = sbf.create(new PayloadBackend(storageName, null));
InputStream streamToWrite = sb.download(storageId);
Map<String, String> userMetadata = sb.getFileMetadata(storageId);
log.info("returned metadata from storageBackend are: {}", userMetadata);
long size = Long.parseLong(userMetadata.get("size"));
String title = userMetadata.get("title");
String contentType = userMetadata.get("content-type");
StreamingOutput so = new SingleFileStreamingOutput(streamToWrite);
return Response
.ok(so)
.header("content-disposition","attachment; filename = "+title)
.header("Content-Length", size)
.header("Content-Type", contentType)
.build();
}
}

View File

@ -1,82 +0,0 @@
package org.gcube.data.access.storagehub.handlers;
import javax.inject.Inject;
import javax.inject.Singleton;
import javax.jcr.ItemNotFoundException;
import javax.jcr.Node;
import javax.jcr.NodeIterator;
import javax.jcr.PathNotFoundException;
import javax.jcr.RepositoryException;
import org.apache.jackrabbit.api.JackrabbitSession;
import org.apache.jackrabbit.api.security.user.Group;
import org.apache.jackrabbit.api.security.user.User;
import org.gcube.common.storagehub.model.exceptions.InvalidCallParameters;
import org.gcube.common.storagehub.model.exceptions.StorageHubException;
import org.gcube.common.storagehub.model.types.NodeProperty;
import org.gcube.data.access.storagehub.Constants;
import org.gcube.data.access.storagehub.PathUtil;
import org.gcube.data.access.storagehub.services.GroupManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@Singleton
public class GroupHandler {
private static final Logger log = LoggerFactory.getLogger(GroupManager.class);
@Inject
PathUtil pathUtil;
public boolean removeUserFromGroup(String groupId, String userId, JackrabbitSession session) throws StorageHubException, RepositoryException {
org.apache.jackrabbit.api.security.user.UserManager usrManager = session.getUserManager();
Group group = (Group)usrManager.getAuthorizable(groupId);
User user = (User)usrManager.getAuthorizable(userId);
if (!group.isMember(user))
throw new InvalidCallParameters("user "+userId+" is not member of group "+groupId);
//delete folder on user
String folderName = group.getPrincipal().getName();
Node folder = getFolderNodeRelatedToGroup(session, folderName);
NodeIterator ni = folder.getSharedSet();
while (ni.hasNext()) {
Node node = ni.nextNode();
if (node.getPath().startsWith(pathUtil.getWorkspacePath(user.getPrincipal().getName()).toPath())) {
node.removeShare();
break;
}
}
return group.removeMember(user);
}
public Node getFolderNodeRelatedToGroup(JackrabbitSession session, String name) throws ItemNotFoundException, RepositoryException {
Node sharedRootNode = session.getNode(Constants.SHARED_FOLDER_PATH);
Node vreFolder = null;
try {
vreFolder = sharedRootNode.getNode(name);
}catch (PathNotFoundException e) {
log.debug("is an old HL VRE");
}
if (vreFolder==null) {
NodeIterator nodes = sharedRootNode.getNodes();
while (nodes.hasNext()) {
Node node = nodes.nextNode();
if (node.hasProperty(NodeProperty.TITLE.toString()) && node.getProperty(NodeProperty.TITLE.toString()).getString().equals(name)) {
vreFolder= node;
break;
}
}
}
if (vreFolder==null) throw new ItemNotFoundException("vre folder not found for group "+name);
return vreFolder;
}
}

View File

@ -0,0 +1,143 @@
package org.gcube.data.access.storagehub.handlers;
import static org.gcube.common.storagehub.model.Constants.enchriptedPrefix;
import static org.gcube.common.storagehub.model.Constants.enchriptedVolatile;
import static org.gcube.common.storagehub.model.Constants.versionPrefix;
import java.util.Base64;
import jakarta.inject.Singleton;
import jakarta.servlet.ServletContext;
import org.gcube.common.encryption.encrypter.StringEncrypter;
import org.gcube.common.security.AuthorizedTasks;
import org.gcube.common.security.secrets.Secret;
import org.gcube.common.storagehub.model.exceptions.BackendGenericError;
import org.gcube.common.storagehub.model.exceptions.StorageHubException;
import org.gcube.data.access.storagehub.types.LinkType;
import org.gcube.data.access.storagehub.types.PublicLink;
import org.gcube.smartgears.ContextProvider;
@Singleton
public class PublicLinkHandler {
public String getForItem(String itemId, ServletContext context) throws BackendGenericError{
return getUrl(itemId, enchriptedPrefix, context);
}
public String getForVersionedItem(String itemId, String version, ServletContext context) throws BackendGenericError {
return getUrl(String.format("%s%s%s",itemId, versionPrefix, version), enchriptedPrefix, context);
}
public String getForVolatile(String fileId, String storageName, ServletContext context) throws BackendGenericError {
return getUrl(String.format("%s_%s",fileId, storageName), enchriptedVolatile, context);
}
public PublicLink resolveEnchriptedId(String enchriptedId) throws StorageHubException {
String complexId = enchriptedId;
boolean isVolatile = false;
if (enchriptedId.startsWith(enchriptedPrefix) || enchriptedId.startsWith(enchriptedVolatile) ) {
final String enchriptedValue = enchriptedId.startsWith(enchriptedPrefix) ? enchriptedPrefix : enchriptedVolatile;
isVolatile = enchriptedId.startsWith(enchriptedVolatile);
try {
String infraContext = String.format("/%s", ContextProvider.get().container().configuration().infrastructure());
Secret infraSecret = ContextProvider.get().container().authorizationProvider().getSecretForContext(infraContext);
complexId = AuthorizedTasks.executeSafely(() -> {
return StringEncrypter.getEncrypter().decrypt(
new String(Base64.getUrlDecoder().decode(enchriptedId.replace(enchriptedValue, ""))));
}, infraSecret);
}catch(Throwable e){
throw new BackendGenericError("invalid public url",e);
}
}
if (isVolatile) {
String[] volatileIdSplit = complexId.split("_");
return new VolatilePublicLink(volatileIdSplit[0], volatileIdSplit[1]);
}else {
if (complexId.contains(versionPrefix)) {
String[] split = complexId.split(versionPrefix);
String itemId = split[0];
String versionName = split[1];
return new ItemPublicLink(itemId, versionName);
} else
return new ItemPublicLink(complexId);
}
}
private String getUrl(String toEnchript, String prefix, ServletContext context) throws BackendGenericError{
String infraContext = String.format("/%s", ContextProvider.get().container().configuration().infrastructure());
Secret infraSecret = ContextProvider.get().container().authorizationProvider().getSecretForContext(infraContext);
try {
String enchriptedQueryString = AuthorizedTasks.executeSafely(
() -> {return StringEncrypter.getEncrypter().encrypt(toEnchript);},infraSecret);
String basepath = context.getInitParameter("resolver-basepath");
String filePublicUrl = String.format("%s/%s%s",basepath, prefix, Base64.getUrlEncoder().encodeToString(enchriptedQueryString.getBytes()));
return filePublicUrl;
}catch (Throwable e) {
throw new BackendGenericError("error encrypting item id",e );
}
}
public static class VolatilePublicLink implements PublicLink {
private String storageKey;
private String storageName;
protected VolatilePublicLink(String storageKey, String storageName){
this.storageKey = storageKey;
this.storageName = storageName;
}
@Override
public LinkType getType() {return LinkType.VOLATILE;}
@Override
public String getId() { return storageKey; }
@Override
public String getStorageName() { return storageName; }
}
public static class ItemPublicLink implements PublicLink {
private String itemId;
private String version;
private LinkType type;
protected ItemPublicLink(String itemId){
this.itemId = itemId;
this.type = LinkType.STANDARD;
}
protected ItemPublicLink(String itemId, String version){
this.itemId = itemId;
this.version = version;
this.type = LinkType.VERSIONED;
}
@Override
public LinkType getType() {return type;}
@Override
public String getId() { return itemId; }
@Override
public String getVersion() { return version; }
}
}

View File

@ -9,8 +9,8 @@ import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.stream.Collectors;
import javax.inject.Inject;
import javax.inject.Singleton;
import jakarta.inject.Inject;
import jakarta.inject.Singleton;
import javax.jcr.ItemNotFoundException;
import javax.jcr.Node;
import javax.jcr.RepositoryException;
@ -18,7 +18,7 @@ import javax.jcr.Session;
import javax.jcr.lock.LockException;
import javax.jcr.version.Version;
import org.gcube.common.authorization.library.AuthorizedTasks;
import org.gcube.common.security.AuthorizedTasks;
import org.gcube.common.storagehub.model.Excludes;
import org.gcube.common.storagehub.model.Paths;
import org.gcube.common.storagehub.model.exceptions.BackendGenericError;
@ -30,7 +30,8 @@ import org.gcube.common.storagehub.model.items.FolderItem;
import org.gcube.common.storagehub.model.items.Item;
import org.gcube.common.storagehub.model.items.TrashItem;
import org.gcube.common.storagehub.model.items.nodes.Content;
import org.gcube.common.storagehub.model.plugins.FolderManager;
import org.gcube.common.storagehub.model.storages.StorageBackend;
import org.gcube.common.storagehub.model.storages.StorageBackendFactory;
import org.gcube.common.storagehub.model.types.ItemAction;
import org.gcube.data.access.storagehub.AuthorizationChecker;
import org.gcube.data.access.storagehub.PathUtil;
@ -38,7 +39,7 @@ import org.gcube.data.access.storagehub.Utils;
import org.gcube.data.access.storagehub.accounting.AccountingHandler;
import org.gcube.data.access.storagehub.handlers.items.Item2NodeConverter;
import org.gcube.data.access.storagehub.handlers.items.Node2ItemConverter;
import org.gcube.data.access.storagehub.handlers.plugins.FolderPluginHandler;
import org.gcube.data.access.storagehub.handlers.plugins.StorageBackendHandler;
import org.gcube.data.access.storagehub.types.ContentPair;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -68,11 +69,9 @@ public class TrashHandler {
@Inject
PathUtil pathUtil;
@Inject FolderPluginHandler managerHandler;
@Inject
FolderPluginHandler folderHandler;
StorageBackendHandler storageBackendHandler;
public void removeNodes(Session ses, List<Item> itemsToDelete) throws RepositoryException, StorageHubException{
log.debug("defnitively removing nodes with ids {}",itemsToDelete);
for (Item item: itemsToDelete) {
@ -109,8 +108,13 @@ public class TrashHandler {
}
try {
FolderManager manager = folderHandler.getFolderManager(item);
contentSet.add(new ContentPair(item.getContent(), manager.getStorageBackend()));
StorageBackendFactory sbf = storageBackendHandler.get(item.getContent().getPayloadBackend());
StorageBackend sb = sbf.create(item.getContent().getPayloadBackend());
contentSet.add(new ContentPair(item.getContent(), sb));
List<Version> versions = versionHandler.getContentVersionHistory((Node)item.getRelatedNode());
@ -118,7 +122,7 @@ public class TrashHandler {
try {
Content content = node2Item.getContentFromVersion(version);
if (content!= null && content.getStorageId()!=null)
contentSet.add(new ContentPair(content, manager.getStorageBackend()));
contentSet.add(new ContentPair(content, sb));
else log.warn("invalid version {}",version.getName());
}catch (Throwable t) {
log.warn("error retrieving version content for {}",version.getName(),t);
@ -159,7 +163,7 @@ public class TrashHandler {
public void run() {
for (ContentPair cp: contentToDelete ) {
try {
cp.getStorageBackend().onDelete(cp.getContent());
cp.getStorageBackend().delete(cp.getContent().getStorageId());
log.debug("file with id {} correctly removed from storage {}",cp.getContent().getStorageId(),cp.getStorageBackend().getClass().getSimpleName());
}catch(Throwable t) {
log.warn("error removing file with id {} from storage {}",cp.getContent().getStorageId(), cp.getStorageBackend().getClass().getSimpleName(), t);
@ -212,8 +216,7 @@ public class TrashHandler {
if (item instanceof FolderItem) {
trashItem.setFolder(true);
}else if (item instanceof AbstractFileItem ) {
AbstractFileItem file = (AbstractFileItem) item;
}else if (item instanceof AbstractFileItem file) {
if (file.getContent()!=null) {
trashItem.setMimeType(file.getContent().getMimeType());
trashItem.setLenght(file.getContent().getSize());
@ -229,10 +232,10 @@ public class TrashHandler {
log.debug("calling jcr move");
ses.getWorkspace().move(nodeToDelete.getPath(), Paths.append(Paths.getPath(newTrashItemNode.getPath()),nodeToDelete.getName()).toPath());
String mimetype = null;
if (item instanceof AbstractFileItem) {
if (((AbstractFileItem)item).getContent()!=null)
mimetype = ((AbstractFileItem) item).getContent().getMimeType();
else log.warn("the AbstractFileItem with id {} has no content (check it!!)", item.getId());
if (item instanceof AbstractFileItem file) {
if (file.getContent()!=null)
mimetype = file.getContent().getMimeType();
else log.warn("the AbstractFileItem with id {} has no content (check it!!)", file.getId());
}
accountingHandler.createFolderRemoveObj(item.getName(), item.getClass().getSimpleName(), mimetype, ses, login, (Node) item.getRelatedNode(), true);
}catch(Throwable t) {

View File

@ -5,8 +5,8 @@ import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.inject.Inject;
import javax.inject.Singleton;
import jakarta.inject.Inject;
import jakarta.inject.Singleton;
import javax.jcr.Node;
import javax.jcr.NodeIterator;
import javax.jcr.RepositoryException;
@ -163,7 +163,7 @@ public class UnshareHandler {
unsharedNodeIdentifier = unsharedNode.getIdentifier();
log.info("[UNSHARE] unshared node id {}",unsharedNodeIdentifier);
ses.save();
}
} //TODO: else shoud I removove all the fiel content ?
log.debug("all the users have been removed, the folder is totally unshared");

View File

@ -4,8 +4,9 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.inject.Singleton;
import jakarta.inject.Singleton;
import javax.jcr.Node;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.jcr.version.Version;
import javax.jcr.version.VersionHistory;
@ -52,7 +53,14 @@ public class VersionHandler {
logger.warn("cannot checkoutNode content node",e);
}
}
public Version getCurrentVersion(Node node) throws RepositoryException{
Session session = node.getSession();
Node contentNode = node.getNode(NodeConstants.CONTENT_NAME);
VersionManager versionManager = session.getWorkspace().getVersionManager();
return versionManager.getBaseVersion(contentNode.getPath());
}
public List<Version> getContentVersionHistory(Node node) {
try {
Session session = node.getSession();
@ -68,10 +76,17 @@ public class VersionHandler {
logger.debug("version name {} with nodeType {}",version.getName(),version.getPrimaryNodeType().getName());
}
return versions;
}catch(Exception e ) {
}catch(Throwable e ) {
logger.warn("cannot get version history content node",e);
return Collections.emptyList();
}
}
public void removeContentVersion(Node node, String versionName) throws RepositoryException{
Node contentNode = node.getNode(NodeConstants.CONTENT_NAME);
VersionHistory history = contentNode.getSession().getWorkspace().getVersionManager().getVersionHistory(contentNode.getPath());
history.removeVersion(versionName);
}
}

View File

@ -7,10 +7,18 @@ import org.gcube.common.storagehub.model.items.nodes.Content;
public interface ContentHandler {
void initiliseSpecificContent(InputStream is, String fileName, String mimeType) throws Exception;
boolean requiresInputStream();
default void initiliseSpecificContent(InputStream is, String fileName, String mimeType, long size) throws Exception{
throw new UnsupportedOperationException();
}
default void initiliseSpecificContent(String fileName, String mimeType) throws Exception {
throw new UnsupportedOperationException();
}
Content getContent();
AbstractFileItem buildItem(String name, String description, String login);
}

View File

@ -4,7 +4,7 @@ import java.util.Arrays;
import java.util.HashMap;
import java.util.Set;
import javax.inject.Singleton;
import jakarta.inject.Singleton;
import org.gcube.common.storagehub.model.annotations.MimeTypeHandler;
import org.reflections.Reflections;
@ -42,9 +42,9 @@ public class ContentHandlerFactory {
public ContentHandler create(String mimetype) throws Exception{
Class<? extends ContentHandler> handlerClass = handlerMap.get(mimetype);
if (handlerClass!=null)
return handlerClass.newInstance();
return handlerClass.getDeclaredConstructor().newInstance();
else
return defaultHandler.newInstance();
return defaultHandler.getDeclaredConstructor().newInstance();
}
}

View File

@ -1,6 +1,5 @@
package org.gcube.data.access.storagehub.handlers.content;
import java.io.InputStream;
import java.util.Calendar;
import org.gcube.common.storagehub.model.items.GenericFileItem;
@ -11,12 +10,17 @@ public class GenericFileHandler implements ContentHandler{
Content content = new Content();
@Override
public void initiliseSpecificContent(InputStream is, String filename, String mimeType) throws Exception {
public boolean requiresInputStream() {
return false;
}
@Override
public void initiliseSpecificContent(String filename, String mimeType) throws Exception {
content.setMimeType(mimeType);
}
@Override
public Content getContent() {
return content;

View File

@ -28,28 +28,38 @@ public class ImageHandler implements ContentHandler{
private static final Logger logger = LoggerFactory.getLogger(ImageHandler.class);
@Override
public void initiliseSpecificContent(InputStream is, String fileName, String mimeType) throws Exception {
Image image = javax.imageio.ImageIO.read(is);
public boolean requiresInputStream() {
return true;
}
int width = image.getWidth(null);
int height = image.getHeight(null);
@Override
public void initiliseSpecificContent(InputStream is, String fileName, String mimeType, long size) throws Exception {
if (size<5242880) {
Image image = javax.imageio.ImageIO.read(is);
content.setWidth(Long.valueOf(width));
content.setHeight(Long.valueOf(height));
int width = image.getWidth(null);
int height = image.getHeight(null);
try {
int[] dimension = getThumbnailDimension(width, height);
byte[] buf = transform(image, fileName, dimension[0], dimension[1]).toByteArray();
content.setWidth(Long.valueOf(width));
content.setHeight(Long.valueOf(height));
content.setThumbnailHeight(Long.valueOf(dimension[1]));
content.setThumbnailWidth(Long.valueOf(dimension[0]));
content.setThumbnailData(buf);
}catch(Throwable t) {
logger.warn("thumbnail for file {} cannot be created ", fileName,t);
try {
int[] dimension = getThumbnailDimension(width, height);
byte[] buf = transform(image, fileName, dimension[0], dimension[1]).toByteArray();
content.setThumbnailHeight(Long.valueOf(dimension[1]));
content.setThumbnailWidth(Long.valueOf(dimension[0]));
content.setThumbnailData(buf);
}catch(Throwable t) {
logger.warn("thumbnail for file {} cannot be created ", fileName,t);
}
}
content.setMimeType(mimeType);
}

View File

@ -17,7 +17,12 @@ public class OfficeAppHandler implements ContentHandler{
Content content = new Content();
@Override
public void initiliseSpecificContent(InputStream is, String filename, String mimeType) throws Exception {
public boolean requiresInputStream() {
return true;
}
@Override
public void initiliseSpecificContent(InputStream is, String filename, String mimeType, long size) throws Exception {
//detecting the file type
BodyContentHandler handler = new BodyContentHandler();
Metadata metadata = new Metadata();

View File

@ -27,7 +27,12 @@ public class PdfHandler implements ContentHandler {
private static final Logger logger = LoggerFactory.getLogger(PdfHandler.class);
@Override
public void initiliseSpecificContent(InputStream is, String fileName, String mimeType) throws Exception {
public boolean requiresInputStream() {
return true;
}
@Override
public void initiliseSpecificContent(InputStream is, String fileName, String mimeType, long size) throws Exception {
try {
PdfReader reader = new PdfReader(is);
content.setNumberOfPages(Long.valueOf(reader.getNumberOfPages()));

View File

@ -10,13 +10,14 @@ import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import javax.inject.Singleton;
import jakarta.inject.Singleton;
import javax.jcr.ItemExistsException;
import javax.jcr.Node;
import javax.jcr.PathNotFoundException;
import javax.jcr.RepositoryException;
import javax.jcr.Value;
import org.apache.jackrabbit.core.NodeImpl;
import org.apache.jackrabbit.util.Text;
import org.apache.jackrabbit.value.BinaryValue;
import org.apache.jackrabbit.value.BooleanValue;
@ -49,52 +50,62 @@ public class Item2NodeConverter {
private static final Logger logger = LoggerFactory.getLogger(Item2NodeConverter.class);
public <T extends RootItem> Node getNode(Node parentNode, T item){
public <T extends RootItem> Node getNode(Node parentNode, T item, String uuid){
try {
String primaryType= ClassHandler.instance().getNodeType(item.getClass());
Node newNode = parentNode.addNode(Text.escapeIllegalJcrChars(item.getName()), primaryType);
//newNode.setPrimaryType(primaryType);
for (Field field : retrieveAllFields(item.getClass())){
if (field.isAnnotationPresent(Attribute.class)){
Attribute attribute = field.getAnnotation(Attribute.class);
if (attribute.isReadOnly()) continue;
field.setAccessible(true);
try{
//Class<?> returnType = field.getType();
logger.trace("creating node - added field {}",field.getName());
Values values = getObjectValue(field.getType(), field.get(item));
if (values.isMulti()) newNode.setProperty(attribute.value(), values.getValues());
else newNode.setProperty(attribute.value(), values.getValue());
} catch (Exception e ) {
logger.warn("error setting value for attribute {}: {}",attribute.value(), e.getMessage());
}
} else if (field.isAnnotationPresent(NodeAttribute.class)){
NodeAttribute nodeAttribute = field.getAnnotation(NodeAttribute.class);
if (nodeAttribute.isReadOnly()) continue;
String nodeName = nodeAttribute.value();
logger.trace("retrieving field node "+field.getName());
field.setAccessible(true);
try{
Object obj = field.get(item);
if (obj!=null)
iterateItemNodeAttributeFields(obj, newNode, nodeName);
} catch (Exception e ) {
logger.debug("error setting value",e);
}
}
}
Node newNode = null;
if (uuid==null)
parentNode.addNode(Text.escapeIllegalJcrChars(item.getName()), primaryType);
else ((NodeImpl)parentNode).addNodeWithUuid(item.getName(), primaryType, uuid);
fillNode(newNode, item);
return newNode;
} catch (RepositoryException e) {
logger.error("error writing repository",e);
throw new RuntimeException(e);
}
}
public <T extends RootItem> Node getNode(Node parentNode, T item){
return getNode(parentNode, item, null);
}
private <T extends RootItem> void fillNode(Node newNode, T item) throws RepositoryException {
for (Field field : retrieveAllFields(item.getClass())){
if (field.isAnnotationPresent(Attribute.class)){
Attribute attribute = field.getAnnotation(Attribute.class);
if (attribute.isReadOnly()) continue;
field.setAccessible(true);
try{
//Class<?> returnType = field.getType();
logger.trace("creating node - added field {}",field.getName());
Values values = getObjectValue(field.getType(), field.get(item));
if (values.isMulti()) newNode.setProperty(attribute.value(), values.getValues());
else newNode.setProperty(attribute.value(), values.getValue());
} catch (Exception e ) {
logger.warn("error setting value for attribute {}: {}",attribute.value(), e.getMessage());
}
} else if (field.isAnnotationPresent(NodeAttribute.class)){
NodeAttribute nodeAttribute = field.getAnnotation(NodeAttribute.class);
if (nodeAttribute.isReadOnly()) continue;
String nodeName = nodeAttribute.value();
logger.trace("retrieving field node "+field.getName());
field.setAccessible(true);
try{
Object obj = field.get(item);
if (obj!=null)
iterateItemNodeAttributeFields(obj, newNode, nodeName);
} catch (Exception e ) {
logger.debug("error setting value",e);
}
}
}
}
@SuppressWarnings("unchecked")
private void iterateItemNodeAttributeFields(Object object, Node parentNode, String nodeName) throws Exception{
AttributeRootNode attributeRootNode = object.getClass().getAnnotation(AttributeRootNode.class);
Node newNode;
@ -115,6 +126,7 @@ public class Item2NodeConverter {
@SuppressWarnings("rawtypes")
Class returnType = field.getType();
Values values = getObjectValue(returnType, field.get(object));
if (values == null) continue;
if (values.isMulti()) newNode.setProperty(attribute.value(), values.getValues());
else newNode.setProperty(attribute.value(), values.getValue());
} catch (Exception e ) {
@ -145,13 +157,28 @@ public class Item2NodeConverter {
iterateItemNodeAttributeFields(obj,newNode, field.getName()+(i++));
}
} else if (field.isAnnotationPresent(NodeAttribute.class)){
NodeAttribute nodeAttribute = field.getAnnotation(NodeAttribute.class);
if (nodeAttribute.isReadOnly()) continue;
String subNodeName = nodeAttribute.value();
logger.trace("retrieving field node "+field.getName());
field.setAccessible(true);
try{
Object obj = field.get(object);
if (obj!=null)
iterateItemNodeAttributeFields(obj, newNode, subNodeName);
} catch (Exception e ) {
logger.debug("error setting value",e);
}
}
}
}
@SuppressWarnings({ "rawtypes" })
public static Values getObjectValue(Class returnType, Object value) throws Exception{
if (value== null) return null;
if (returnType.equals(String.class)) return new Values(new StringValue((String) value));
if (returnType.isEnum()) return new Values(new StringValue(((Enum) value).toString()));
if (returnType.equals(Calendar.class)) return new Values(new DateValue((Calendar) value));
@ -188,8 +215,9 @@ public class Item2NodeConverter {
public <F extends AbstractFileItem> void replaceContent(Node node, F item, ItemAction action){
try {
node.setPrimaryType(item.getClass().getAnnotation(RootNode.class).value());
String primaryType = item.getClass().getAnnotation(RootNode.class).value()[0];
node.setPrimaryType(primaryType);
Node contentNode = node.getNode(NodeConstants.CONTENT_NAME);
contentNode.setPrimaryType(item.getContent().getClass().getAnnotation(AttributeRootNode.class).value());
@ -197,22 +225,9 @@ public class Item2NodeConverter {
node.setProperty(NodeProperty.LAST_MODIFIED_BY.toString(), item.getLastModifiedBy());
node.setProperty(NodeProperty.LAST_ACTION.toString(), action.name());
for (Field field : retrieveAllFields(item.getContent().getClass())){
if (field.isAnnotationPresent(Attribute.class)){
Attribute attribute = field.getAnnotation(Attribute.class);
if (attribute.isReadOnly()) continue;
field.setAccessible(true);
try{
//Class<?> returnType = field.getType();
Values values = getObjectValue(field.getType(), field.get(item.getContent()));
if (values.isMulti()) contentNode.setProperty(attribute.value(), values.getValues() );
else contentNode.setProperty(attribute.value(), values.getValue());
} catch (Exception e ) {
logger.debug("error setting value for attribute "+attribute.value(),e);
}
}
}
replaceContentNodeInternal(contentNode, item.getContent().getClass(),item.getContent());
} catch (RepositoryException e) {
logger.error("error writing repository",e);
@ -220,7 +235,41 @@ public class Item2NodeConverter {
}
}
//VALID ONLY FOR CONTENT
public void replaceContentNodeInternal(Node node, Class<?> clazz, Object instance) {
for (Field field : retrieveAllFields(clazz)){
if (field.isAnnotationPresent(Attribute.class)){
Attribute attribute = field.getAnnotation(Attribute.class);
if (attribute.isReadOnly()) continue;
field.setAccessible(true);
try{
//Class<?> returnType = field.getType();
Values values = getObjectValue(field.getType(), field.get(instance));
if (values.isMulti()) node.setProperty(attribute.value(), values.getValues() );
else node.setProperty(attribute.value(), values.getValue());
} catch (Exception e ) {
logger.debug("error setting value for attribute "+attribute.value(),e);
}
} else if (field.isAnnotationPresent(NodeAttribute.class)){
NodeAttribute nodeAttribute = field.getAnnotation(NodeAttribute.class);
if (nodeAttribute.isReadOnly()) continue;
String subNodeName = nodeAttribute.value();
logger.trace("retrieving field node "+field.getName());
field.setAccessible(true);
try{
Object obj = field.get(instance);
if (obj!=null)
iterateItemNodeAttributeFields(obj, node, subNodeName);
} catch (Exception e ) {
logger.debug("error setting value",e);
}
}
}
}
public void updateHidden(Node node, Boolean hidden,String login) throws RepositoryException {
Utils.setPropertyOnChangeNode(node, login, ItemAction.UPDATED);
node.setProperty(NodeProperty.HIDDEN.toString(), hidden);
@ -231,6 +280,7 @@ public class Item2NodeConverter {
node.setProperty(NodeProperty.DESCRIPTION.toString(), description);
}
@SuppressWarnings("unchecked")
public void updateOwnerOnSubTree(Node node, String owner) throws RepositoryException, BackendGenericError {
Class<? extends Item> classToHandle = (Class<? extends Item>)ClassHandler.instance().get(node.getPrimaryNodeType().getName());
if (classToHandle==null) return;

View File

@ -1,23 +1,19 @@
package org.gcube.data.access.storagehub.handlers.items;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import javax.inject.Inject;
import javax.inject.Singleton;
import jakarta.inject.Inject;
import jakarta.inject.Singleton;
import javax.jcr.Node;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.jcr.lock.LockException;
import javax.jcr.version.Version;
import org.apache.commons.compress.archivers.ArchiveEntry;
import org.apache.commons.compress.archivers.ArchiveInputStream;
@ -26,7 +22,6 @@ import org.apache.tika.config.TikaConfig;
import org.apache.tika.detect.Detector;
import org.apache.tika.io.TikaInputStream;
import org.apache.tika.metadata.Metadata;
import org.gcube.common.authorization.library.AuthorizedTasks;
import org.gcube.common.storagehub.model.Excludes;
import org.gcube.common.storagehub.model.NodeConstants;
import org.gcube.common.storagehub.model.Paths;
@ -38,12 +33,11 @@ import org.gcube.common.storagehub.model.exceptions.ItemLockedException;
import org.gcube.common.storagehub.model.exceptions.StorageHubException;
import org.gcube.common.storagehub.model.items.AbstractFileItem;
import org.gcube.common.storagehub.model.items.FolderItem;
import org.gcube.common.storagehub.model.plugins.FolderManager;
import org.gcube.common.storagehub.model.storages.MetaInfo;
import org.gcube.common.storagehub.model.storages.StorageBackend;
import org.gcube.common.storagehub.model.storages.StorageBackendFactory;
import org.gcube.common.storagehub.model.types.ItemAction;
import org.gcube.data.access.storagehub.AuthorizationChecker;
import org.gcube.data.access.storagehub.MultipleOutputStream;
import org.gcube.data.access.storagehub.Utils;
import org.gcube.data.access.storagehub.accounting.AccountingHandler;
import org.gcube.data.access.storagehub.handlers.VersionHandler;
@ -55,15 +49,15 @@ import org.gcube.data.access.storagehub.handlers.items.builders.FileCreationPara
import org.gcube.data.access.storagehub.handlers.items.builders.FolderCreationParameters;
import org.gcube.data.access.storagehub.handlers.items.builders.GCubeItemCreationParameters;
import org.gcube.data.access.storagehub.handlers.items.builders.URLCreationParameters;
import org.gcube.data.access.storagehub.handlers.plugins.FolderPluginHandler;
import org.gcube.data.access.storagehub.handlers.plugins.StorageBackendHandler;
import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@Singleton
public class ItemHandler {
@Inject
@Inject
AccountingHandler accountingHandler;
@Inject
@ -76,43 +70,48 @@ public class ItemHandler {
VersionHandler versionHandler;
@Inject
FolderPluginHandler pluginHandler;
StorageBackendHandler storageBackendHandler;
private static ExecutorService executor = Executors.newFixedThreadPool(100);
// private static ExecutorService executor = Executors.newFixedThreadPool(100);
@Inject Node2ItemConverter node2Item;
@Inject Item2NodeConverter item2Node;
@Inject
Node2ItemConverter node2Item;
@Inject
Item2NodeConverter item2Node;
private static Logger log = LoggerFactory.getLogger(ItemHandler.class);
public <T extends CreateParameters> String create(T parameters) throws Exception{
// TODO: accounting
// provider URI host
// resourceOwner user
// consumer write
// in caso di versione - update con -delta
public <T extends CreateParameters> String create(T parameters) throws Exception {
Session ses = parameters.getSession();
Node destination;
try {
destination = ses.getNodeByIdentifier(parameters.getParentId());
}catch(RepositoryException inf) {
} catch (RepositoryException inf) {
throw new IdNotFoundException(parameters.getParentId());
}
if (!node2Item.checkNodeType(destination, FolderItem.class))
if (!node2Item.checkNodeType(destination, FolderItem.class))
throw new InvalidItemException("the destination item is not a folder");
authChecker.checkWriteAuthorizationControl(ses, parameters.getUser(), destination.getIdentifier(), true);
try {
Node newNode = null;
switch (parameters.getMangedType()) {
case FILE:
newNode = create((FileCreationParameters)parameters, destination);
newNode = create((FileCreationParameters) parameters, destination);
break;
case FOLDER:
newNode = create((FolderCreationParameters)parameters, destination);
newNode = create((FolderCreationParameters) parameters, destination);
break;
case ARCHIVE:
newNode = create((ArchiveStructureCreationParameter)parameters, destination);
newNode = create((ArchiveStructureCreationParameter) parameters, destination);
break;
case URL:
newNode = create((URLCreationParameters) parameters, destination);
@ -123,7 +122,7 @@ public class ItemHandler {
default:
throw new InvalidCallParameters("Item not supported");
}
log.debug("item with id {} correctly created",newNode.getIdentifier());
log.debug("item with id {} correctly created", newNode.getIdentifier());
return newNode.getIdentifier();
} finally {
if (parameters.getSession().getWorkspace().getLockManager().isLocked(destination.getPath()))
@ -132,267 +131,289 @@ public class ItemHandler {
}
private Node create(FolderCreationParameters params, Node destination) throws Exception{
private Node create(FolderCreationParameters params, Node destination) throws Exception {
Utils.acquireLockWithWait(params.getSession(), destination.getPath(), false, params.getUser(), 10);
Node newNode = Utils.createFolderInternally(params, accountingHandler);
Node newNode = Utils.createFolderInternally(params, accountingHandler, false);
params.getSession().save();
return newNode;
}
private Node create(FileCreationParameters params, Node destination) throws Exception{
Node newNode = createFileItemInternally(params.getSession(), destination, params.getStream(), params.getName(), params.getDescription(), params.getUser(), true);
private Node create(FileCreationParameters params, Node destination) throws Exception {
Node newNode = createFileItemInternally(params.getSession(), destination, params.getStream(), params.getName(),
params.getDescription(), params.getFileDetails(), params.getUser(), true);
params.getSession().save();
versionHandler.checkinContentNode(newNode);
log.info("file with id {} correctly created",newNode.getIdentifier());
return newNode;
return newNode;
}
private Node create(URLCreationParameters params, Node destination) throws Exception{
private Node create(URLCreationParameters params, Node destination) throws Exception {
Utils.acquireLockWithWait(params.getSession(), destination.getPath(), false, params.getUser(), 10);
Node newNode = Utils.createURLInternally(params.getSession(), destination, params.getName(), params.getUrl(), params.getDescription(), params.getUser(), accountingHandler);
Node newNode = Utils.createURLInternally(params.getSession(), destination, params.getName(), params.getUrl(),
params.getDescription(), params.getUser(), accountingHandler);
params.getSession().save();
return newNode;
}
private Node create(ArchiveStructureCreationParameter params, Node destination) throws Exception{
private Node create(ArchiveStructureCreationParameter params, Node destination) throws Exception {
Utils.acquireLockWithWait(params.getSession(), destination.getPath(), false, params.getUser(), 10);
FolderCreationParameters folderParameters = FolderCreationParameters.builder().name(params.getParentFolderName()).author(params.getUser()).on(destination.getIdentifier()).with(params.getSession()).build();
Node parentDirectoryNode = Utils.createFolderInternally(folderParameters, accountingHandler);
FolderCreationParameters folderParameters = FolderCreationParameters.builder()
.name(params.getParentFolderName()).author(params.getUser()).on(destination.getIdentifier())
.with(params.getSession()).build();
Node parentDirectoryNode = Utils.createFolderInternally(folderParameters, accountingHandler, false);
params.getSession().save();
try {
if (params.getSession().getWorkspace().getLockManager().isLocked(destination.getPath()))
params.getSession().getWorkspace().getLockManager().unlock(destination.getPath());
} catch (Throwable t){
} catch (Throwable t) {
log.warn("error unlocking {}", destination.getPath(), t);
}
Set<Node> fileNodes = new HashSet<>();
HashMap<String, Node> directoryNodeMap = new HashMap<>();
HashMap<String, Node> directoryNodeMap = new HashMap<>();
try (ArchiveInputStream input = new ArchiveStreamFactory()
.createArchiveInputStream(new BufferedInputStream(params.getStream(), 1024*64))){
ArchiveEntry entry;
while ((entry = input.getNextEntry()) != null) {
String entirePath = entry.getName();
if (entry.isDirectory()) {
log.debug("creating directory with entire path {} ", entirePath);
createPath(entirePath, directoryNodeMap, parentDirectoryNode, params.getSession(), params.getUser());
continue;
} else {
try {
String name = entirePath.replaceAll("([^/]*/)*(.*)", "$2");
String parentPath = entirePath.replaceAll("(([^/]*/)*)(.*)", "$1");
log.debug("creating file with entire path {}, name {}, parentPath {} ", entirePath, name, parentPath);
Node fileNode = null;
if (parentPath.isEmpty())
fileNode = createFileItemInternally(params.getSession(), parentDirectoryNode, input, name, "", params.getUser(), false);
else {
Node parentNode = directoryNodeMap.get(parentPath);
if (parentNode ==null)
parentNode = createPath(parentPath, directoryNodeMap, parentDirectoryNode, params.getSession(), params.getUser());
fileNode = createFileItemInternally(params.getSession(), parentNode, input, name, "", params.getUser(), false);
}
fileNodes.add(fileNode);
}catch(Exception e) {
log.warn("error getting file {}",entry.getName(),e);
ArchiveInputStream input = new ArchiveStreamFactory()
.createArchiveInputStream(new BufferedInputStream(params.getStream()));
ArchiveEntry entry;
while ((entry = input.getNextEntry()) != null) {
String entirePath = entry.getName();
log.debug("reading new entry ------> {} ", entirePath);
if (entry.isDirectory()) {
log.debug("creating directory with entire path {} ", entirePath);
createPath(entirePath, directoryNodeMap, parentDirectoryNode, params.getSession(), params.getUser());
} else {
try {
String name = entirePath.replaceAll("([^/]*/)*(.*)", "$2");
String parentPath = entirePath.replaceAll("(([^/]*/)*)(.*)", "$1");
log.debug("creating file with entire path {}, name {}, parentPath {} ", entirePath, name,
parentPath);
Node fileNode = null;
long fileSize = entry.getSize();
FormDataContentDisposition fileDetail = FormDataContentDisposition.name(name).size(fileSize)
.build();
if (parentPath.isEmpty()) {
fileNode = createFileItemInternally(params.getSession(), parentDirectoryNode, input, name, "",
fileDetail, params.getUser(), false);
} else {
Node parentNode = directoryNodeMap.get(parentPath);
if (parentNode == null)
parentNode = createPath(parentPath, directoryNodeMap, parentDirectoryNode,
params.getSession(), params.getUser());
fileNode = createFileItemInternally(params.getSession(), parentNode, input, name, "",
fileDetail, params.getUser(), false);
}
fileNodes.add(fileNode);
} catch (Throwable e) {
log.warn("error getting file {}", entry.getName(), e);
}
}
}
log.info("archive {} uploading finished ", params.getParentFolderName());
params.getSession().save();
for (Node node : fileNodes)
versionHandler.checkinContentNode(node);
return parentDirectoryNode;
}
private Node createPath(String parentPath, Map<String, Node> directoryNodeMap, Node rootNode, Session ses, String user) throws StorageHubException, RepositoryException{
private Node createPath(String parentPath, Map<String, Node> directoryNodeMap, Node rootNode, Session ses,
String user) throws StorageHubException, RepositoryException {
String[] parentPathSplit = parentPath.split("/");
String name = parentPathSplit[parentPathSplit.length-1];
String name = parentPathSplit[parentPathSplit.length - 1];
StringBuilder relParentPath = new StringBuilder();
for (int i = 0 ; i<=parentPathSplit.length-2; i++)
for (int i = 0; i <= parentPathSplit.length - 2; i++)
relParentPath.append(parentPathSplit[i]).append("/");
if (relParentPath.toString().isEmpty()) {
FolderCreationParameters folderParameters = FolderCreationParameters.builder().name(name).author(user).on(rootNode.getIdentifier()).with(ses).build();
Node createdNode = Utils.createFolderInternally(folderParameters, accountingHandler);
directoryNodeMap.put(name+"/", createdNode);
FolderCreationParameters folderParameters = FolderCreationParameters.builder().name(name).author(user)
.on(rootNode.getIdentifier()).with(ses).build();
Node createdNode = Utils.createFolderInternally(folderParameters, accountingHandler, false);
directoryNodeMap.put(name + "/", createdNode);
return createdNode;
}else {
} else {
Node relParentNode = directoryNodeMap.get(relParentPath.toString());
if (relParentNode==null) {
if (relParentNode == null) {
relParentNode = createPath(relParentPath.toString(), directoryNodeMap, rootNode, ses, user);
}
FolderCreationParameters folderParameters = FolderCreationParameters.builder().name(name).author(user).on(relParentNode.getIdentifier()).with(ses).build();
Node createdNode = Utils.createFolderInternally(folderParameters, accountingHandler);
FolderCreationParameters folderParameters = FolderCreationParameters.builder().name(name).author(user)
.on(relParentNode.getIdentifier()).with(ses).build();
Node createdNode = Utils.createFolderInternally(folderParameters, accountingHandler, false);
directoryNodeMap.put(relParentPath.append(name).append("/").toString(), createdNode);
return createdNode;
}
}
private Node create(GCubeItemCreationParameters params, Node destination) throws Exception{
private Node create(GCubeItemCreationParameters params, Node destination) throws Exception {
Utils.acquireLockWithWait(params.getSession(), destination.getPath(), false, params.getUser(), 10);
Node newNode = Utils.createGcubeItemInternally(params.getSession(), destination, params.getItem().getName(), params.getItem().getDescription(), params.getUser(), params.getItem(), accountingHandler);
Node newNode = Utils.createGcubeItemInternally(params.getSession(), destination, params.getItem().getName(),
params.getItem().getDescription(), params.getUser(), params.getItem(), accountingHandler);
params.getSession().save();
return newNode;
}
private Node createFileItemInternally(Session ses, Node destinationNode, InputStream stream, String name, String description, String login, boolean withLock) throws RepositoryException, StorageHubException{
private Node createFileItemInternally(Session ses, Node destinationNode, InputStream stream, String name,
String description, FormDataContentDisposition fileDetails, String login, boolean withLock)
throws RepositoryException, StorageHubException {
log.trace("UPLOAD: starting preparing file");
Node newNode;
FolderItem destinationItem = node2Item.getItem(destinationNode, Excludes.ALL);
FolderManager folderManager = pluginHandler.getFolderManager(destinationItem);
StorageBackend storageBackend = folderManager.getStorageBackend();
StorageBackendFactory sbf = storageBackendHandler.get(destinationItem.getBackend());
StorageBackend sb = sbf.create(destinationItem.getBackend());
String relativePath = destinationNode.getPath();
if (destinationItem.isExternalManaged())
relativePath = relativePath.replace(folderManager.getRootFolder().getPath(), "");
String newNodePath = Paths.append(Paths.getPath(destinationNode.getPath()), name).toPath();
log.info("new node path is {}", newNodePath);
if (ses.nodeExists(newNodePath)) {
if (!folderManager.manageVersion())
throw new InvalidCallParameters("storage for plugin "+folderManager.getClass().getName()+" doesn't support versioning");
newNode = ses.getNode(newNodePath);
authChecker.checkWriteAuthorizationControl(ses, login, newNode.getIdentifier(), false);
AbstractFileItem item = fillItemWithContent(stream, storageBackend, name, description, relativePath,login);
AbstractFileItem item = fillItemWithContent(stream, sb, name, description, fileDetails, relativePath,
login);
if (withLock) {
try {
ses.getWorkspace().getLockManager().lock(newNode.getPath(), true, true, 0,login);
}catch (LockException le) {
ses.getWorkspace().getLockManager().lock(newNode.getPath(), true, true, 0, login);
} catch (LockException le) {
throw new ItemLockedException(le);
}
}
try {
versionHandler.checkoutContentNode(newNode);
log.trace("replacing content of class {}",item.getContent().getClass());
item2Node.replaceContent(newNode,item, ItemAction.UPDATED);
accountingHandler.createFileUpdated(item.getTitle(), ses, newNode, login, false);
log.trace("replacing content of class {}", item.getContent().getClass());
item2Node.replaceContent(newNode, item, ItemAction.UPDATED);
String versionName = null;
try {
Version version = versionHandler.getCurrentVersion(newNode);
versionName = version.getName();
} catch (RepositoryException e) {
log.warn("current version of {} cannot be retreived", item.getId());
}
accountingHandler.createFileUpdated(item.getTitle(), versionName, ses, newNode, login, false);
ses.save();
}finally {
if (withLock) ses.getWorkspace().getLockManager().unlock(newNode.getPath());
} catch (Throwable t) {
log.error("error saving item", t);
} finally {
if (withLock) {
if (ses != null && ses.hasPendingChanges())
ses.save();
ses.getWorkspace().getLockManager().unlock(newNode.getPath());
}
}
}
else {
} else {
authChecker.checkWriteAuthorizationControl(ses, login, destinationNode.getIdentifier(), true);
AbstractFileItem item = fillItemWithContent(stream, storageBackend, name, description, relativePath, login);
AbstractFileItem item = fillItemWithContent(stream, sb, name, description, fileDetails, relativePath,
login);
if (withLock) {
try {
log.debug("trying to acquire lock");
Utils.acquireLockWithWait(ses, destinationNode.getPath(), false, login, 10);
}catch (LockException le) {
} catch (LockException le) {
throw new ItemLockedException(le);
}
}
try {
newNode = item2Node.getNode(destinationNode, item);
newNode = item2Node.getNode(destinationNode, item);
accountingHandler.createEntryCreate(item.getTitle(), ses, newNode, login, false);
ses.save();
}finally {
if (withLock) ses.getWorkspace().getLockManager().unlock(destinationNode.getPath());
} catch (Throwable t) {
log.error("error saving item", t);
throw new BackendGenericError(t);
} finally {
if (withLock)
ses.getWorkspace().getLockManager().unlock(destinationNode.getPath());
}
versionHandler.makeVersionableContent(newNode);
accountingHandler.createFolderAddObj(name, item.getClass().getSimpleName(), item.getContent().getMimeType(), ses, login, destinationNode, false);
accountingHandler.createFolderAddObj(name, item.getClass().getSimpleName(), item.getContent().getMimeType(),
ses, login, destinationNode, false);
}
// TODO: Utils.updateParentSize()
return newNode;
}
private AbstractFileItem fillItemWithContent(InputStream stream, StorageBackend storageBackend, String name, String description, String relPath, String login) throws BackendGenericError{
ContentHandler handler = getContentHandler(stream, storageBackend, name, relPath, login);
AbstractFileItem item =handler.buildItem(name, description, login);
return item ;
private AbstractFileItem fillItemWithContent(InputStream stream, StorageBackend storageBackend, String name,
String description, FormDataContentDisposition fileDetails, String relPath, String login)
throws BackendGenericError {
log.trace("UPLOAD: filling content");
ContentHandler handler = getContentHandler(stream, storageBackend, name, fileDetails, relPath, login);
AbstractFileItem item = handler.buildItem(name, description, login);
return item;
}
private ContentHandler getContentHandler(InputStream stream, StorageBackend storageBackend, String name, String relPath, String login) throws BackendGenericError {
private ContentHandler getContentHandler(InputStream stream, StorageBackend storageBackend, String name,
FormDataContentDisposition fileDetails, String relPath, String login) throws BackendGenericError {
final MultipleOutputStream mos;
try{
mos = new MultipleOutputStream(stream, 2);
}catch (IOException e) {
throw new BackendGenericError(e);
}
Callable<ContentHandler> mimeTypeDector = new Callable<ContentHandler>() {
@Override
public ContentHandler call() throws Exception {
ContentHandler handler =null;
long start = System.currentTimeMillis();
log.debug("TIMING: reading the mimetype - start");
try(InputStream is1 = new BufferedInputStream(mos.get(), 1024*64)){
org.apache.tika.mime.MediaType mediaType = null;
TikaConfig config = TikaConfig.getDefaultConfig();
Detector detector = config.getDetector();
TikaInputStream stream = TikaInputStream.get(is1);
Metadata metadata = new Metadata();
metadata.add(Metadata.RESOURCE_NAME_KEY, name);
mediaType = detector.detect(stream, metadata);
String mimeType = mediaType.getBaseType().toString();
handler = contenthandlerFactory.create(mimeType);
is1.reset();
handler.initiliseSpecificContent(is1, name, mimeType);
log.trace("TIMING: reading the mimetype - finished in {}",System.currentTimeMillis()-start);
} catch (Throwable e) {
log.error("error retrieving mimeType",e);
throw new RuntimeException(e);
}
return handler;
}
};
Callable<MetaInfo> uploader = new Callable<MetaInfo>() {
@Override
public MetaInfo call() throws Exception {
try(InputStream is1 = mos.get()){
MetaInfo info = storageBackend.upload(is1, relPath, name);
return info;
}catch (Throwable e) {
log.error("error writing content",e );
throw e;
}
}
};
Future<ContentHandler> detectorF = executor.submit(AuthorizedTasks.bind(mimeTypeDector));
Future<MetaInfo> uploaderF = executor.submit(AuthorizedTasks.bind(uploader));
log.trace("UPLOAD: handling content");
long start = System.currentTimeMillis();
log.debug("TIMING: writing the stream - start");
log.trace("UPLOAD: writing the stream - start");
try {
mos.startWriting();
log.debug("TIMING: writing the stream - finished in {}",System.currentTimeMillis()-start);
ContentHandler handler = detectorF.get();
MetaInfo info = uploaderF.get();
MetaInfo info = null;
try {
log.debug("UPLOAD: upload on {} - start", storageBackend.getClass());
if (fileDetails != null && fileDetails.getSize() > 0) {
log.debug("UPLOAD: file size set is {} Byte", fileDetails.getSize());
info = storageBackend.upload(stream, relPath, name, fileDetails.getSize(), login);
} else
info = storageBackend.upload(stream, relPath, name, login);
log.debug("UPLOAD: upload on storage - stop");
} catch (Throwable e) {
log.error("error writing content", e);
throw e;
}
ContentHandler handler = null;
String mimeType;
log.debug("UPLOAD: reading the mimetype - start");
try (InputStream is1 = new BufferedInputStream(storageBackend.download(info.getStorageId()))) {
org.apache.tika.mime.MediaType mediaType = null;
TikaConfig config = TikaConfig.getDefaultConfig();
Detector detector = config.getDetector();
TikaInputStream tikastream = TikaInputStream.get(is1);
Metadata metadata = new Metadata();
mediaType = detector.detect(tikastream, metadata);
mimeType = mediaType.getBaseType().toString();
handler = contenthandlerFactory.create(mimeType);
log.debug("UPLOAD: reading the mimetype {} - finished in {}", mimeType,
System.currentTimeMillis() - start);
} catch (Throwable e) {
log.error("error retrieving mimeType", e);
throw new RuntimeException(e);
}
if (handler.requiresInputStream())
try (InputStream is1 = new BufferedInputStream(storageBackend.download(info.getStorageId()))) {
log.debug("UPLOAD: the file type requires input stream");
handler.initiliseSpecificContent(is1, name, mimeType, info.getSize());
}
else {
log.debug("UPLOAD: the file type doesn't requires input stream");
handler.initiliseSpecificContent(name, mimeType);
}
log.debug("UPLOAD: writing the stream - finished in {}", System.currentTimeMillis() - start);
handler.getContent().setData(NodeConstants.CONTENT_NAME);
handler.getContent().setStorageId(info.getStorageId());
handler.getContent().setSize(info.getSize());
handler.getContent().setRemotePath(info.getRemotePath());
handler.getContent().setRemotePath(info.getRemotePath());
handler.getContent().setPayloadBackend(info.getPayloadBackend());
log.debug("UPLOAD: content payload set as {} ", handler.getContent().getPayloadBackend());
return handler;
}catch (Exception e) {
} catch (Throwable e) {
log.error("error writing file", e);
throw new BackendGenericError(e);
}

View File

@ -13,7 +13,7 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.inject.Singleton;
import jakarta.inject.Singleton;
import javax.jcr.Node;
import javax.jcr.NodeIterator;
import javax.jcr.PathNotFoundException;
@ -83,7 +83,7 @@ public class Node2ItemConverter {
setGenericFields(node.getFrozenNode(), Content.class, null, content);
return content;
}
public Message getMessageItem(Node node) throws RepositoryException{
if (!(node.getPrimaryNodeType().getName().equals("nthl:itemSentRequest")
|| node.getPrimaryNodeType().getName().equals("nthl:itemSentRequestSH")))
@ -95,7 +95,7 @@ public class Node2ItemConverter {
}catch (Throwable e) {
msg.setWithAttachments(false);
}
setRootItemCommonFields(node, Collections.emptyList(), Message.class, msg);
return msg;
}
@ -104,7 +104,7 @@ public class Node2ItemConverter {
private <T extends Item> T retrieveItem(Node node, List<String> excludes, Class<T> classToHandle) throws RepositoryException, BackendGenericError{
T item;
try {
item = classToHandle.newInstance();
item = classToHandle.getDeclaredConstructor().newInstance();
}catch (Exception e) {
throw new BackendGenericError(e);
}
@ -129,7 +129,7 @@ public class Node2ItemConverter {
item.setExternalManaged(false);
}
item.setLocked(node.isLocked());
setRootItemCommonFields(node, excludes, classToHandle, item);
@ -137,7 +137,7 @@ public class Node2ItemConverter {
return item;
}
private <T extends Item> boolean hasTypedParent(Node node, Class<T> parentType) throws BackendGenericError, RepositoryException{
if(node==null) return false;
@ -146,16 +146,16 @@ public class Node2ItemConverter {
private <T extends RootItem> void setRootItemCommonFields(Node node, List<String> excludes, Class<T> classToHandle, T instance) throws RepositoryException{
try{
instance.setParentId(node.getParent().getIdentifier());
instance.setParentPath(node.getParent().getPath());
}catch (Throwable e) {
logger.trace("Root node doesn't have a parent");
}
instance.setRelatedNode(node);
instance.setId(node.getIdentifier());
instance.setName(Text.unescapeIllegalJcrChars(node.getName()));
@ -166,21 +166,11 @@ public class Node2ItemConverter {
setGenericFields(node, classToHandle, excludes, instance);
}
private <T> void setGenericFields(Node node, Class<T> classToHandle,List<String> excludes, T instance){
for (Field field : retrieveAllFields(classToHandle)){
if (field.isAnnotationPresent(Attribute.class)){
Attribute attribute = field.getAnnotation(Attribute.class);
field.setAccessible(true);
try{
Class<?> returnType = field.getType();
field.set(instance, getPropertyValue(returnType, node.getProperty(attribute.value())));
logger.trace("retrieve item - added field {}",field.getName());
}catch(PathNotFoundException e){
logger.trace("the current node dosn't contain {} property",attribute.value());
} catch (Exception e ) {
logger.debug("error setting value for property {} ",attribute.value());
}
setAttributeFieldCheckingDefault(field, instance, node);
} else if (field.isAnnotationPresent(NodeAttribute.class)){
String fieldNodeName = field.getAnnotation(NodeAttribute.class).value();
//for now it excludes only first level node
@ -195,7 +185,7 @@ public class Node2ItemConverter {
}catch(PathNotFoundException e){
logger.trace("the current node dosn't contain {} node",fieldNodeName);
} catch (Exception e ) {
logger.debug("error setting value",e);
logger.trace("error setting value",e);
}
@ -204,100 +194,145 @@ public class Node2ItemConverter {
}
private <T> T iterateNodeAttributeFields(Class<T> clazz, Node node) throws Exception{
T obj = clazz.newInstance();
T obj = clazz.getDeclaredConstructor().newInstance();
for (Field field : retrieveAllFields(clazz)){
if (field.isAnnotationPresent(Attribute.class)){
Attribute attribute = field.getAnnotation(Attribute.class);
field.setAccessible(true);
try{
Class returnType = field.getType();
field.set(obj, getPropertyValue(returnType, node.getProperty(attribute.value())));
}catch(PathNotFoundException e){
logger.trace("the current node dosn't contain {} property",attribute.value());
} catch (Exception e ) {
logger.debug("error setting value {}",e.getMessage());
}
setAttributeFieldCheckingDefault(field, obj, node);
} else if (field.isAnnotationPresent(MapAttribute.class)){
logger.trace("found field {} of type annotated as MapAttribute in class {} and node name {}", field.getName(), clazz.getName(), node.getName());
field.setAccessible(true);
String exclude = field.getAnnotation(MapAttribute.class).excludeStartWith();
Map<String, Object> mapToset = new HashMap<String, Object>();
PropertyIterator iterator = node.getProperties();
if (iterator!=null) {
while (iterator.hasNext()){
Property prop = iterator.nextProperty();
if (!exclude.isEmpty() && prop.getName().startsWith(exclude)) continue;
try{
logger.trace("adding {} in the map",prop.getName());
mapToset.put(prop.getName(), getPropertyValue(prop));
}catch(PathNotFoundException e){
logger.warn("the property {} is not mapped",prop.getName());
} catch (Exception e ) {
logger.debug("error setting value {}",e.getMessage());
}
}
}
field.set(obj, mapToset);
setMapAttribute(field, obj, node);
} else if (field.isAnnotationPresent(ListNodes.class)){
logger.trace("found field {} of type annotated as ListNodes in class {} on node {}", field.getName(), clazz.getName(), node.getName());
setListNode(field, obj, node);
} else if (field.isAnnotationPresent(NodeAttribute.class)){
logger.trace("found field {} of type annotated as NodeAttribute in class {} on node {}", field.getName(), clazz.getName(), node.getName());
String fieldNodeName = field.getAnnotation(NodeAttribute.class).value();
//for now it excludes only first level node
//if (excludes!=null && excludes.contains(fieldNodeName)) continue;
//for now it excludes only first level node
logger.trace("retrieving field node {} on field {}", fieldNodeName, field.getName());
field.setAccessible(true);
String exclude = field.getAnnotation(ListNodes.class).excludeTypeStartWith();
String include = field.getAnnotation(ListNodes.class).includeTypeStartWith();
Class listType = field.getAnnotation(ListNodes.class).listClass();
Map<String, Class> subTypesMap = Collections.emptyMap();
if (!typeToSubtypeMap.containsKey(listType)) {
Configuration config = new ConfigurationBuilder().forPackages(listType.getPackage().getName());
Reflections reflections = new Reflections(config);
Set<Class> subTypes = reflections.getSubTypesOf(listType);
if (subTypes.size()>0) {
subTypesMap = new HashMap<>();
for (Class subtype: subTypes)
if (subtype.isAnnotationPresent(AttributeRootNode.class)) {
AttributeRootNode attributeRootNode = (AttributeRootNode)subtype.getAnnotation(AttributeRootNode.class);
subTypesMap.put(attributeRootNode.value(), subtype);
}
} else logger.trace("no subtypes found for {}",listType.getName());
typeToSubtypeMap.put(listType, subTypesMap);
} else {
logger.info("subtypes already found in cache");
subTypesMap = typeToSubtypeMap.get(listType);
try{
Node fieldNode = node.getNode(fieldNodeName);
logger.trace("looking in node {} searched with {}",fieldNode.getName(),fieldNodeName);
field.set(obj, iterateNodeAttributeFields(field.getType(), fieldNode));
}catch(PathNotFoundException e){
logger.warn("the current node dosn't contain {} node",fieldNodeName);
} catch (Exception e ) {
logger.warn("error setting value",e);
}
List<Object> toSetList = new ArrayList<>();
NodeIterator iterator = node.getNodes();
while (iterator.hasNext()){
Node currentNode = iterator.nextNode();
String primaryType = currentNode.getPrimaryNodeType().getName();
logger.trace("the current node {} has a list",currentNode.getName());
if (!include.isEmpty() && !primaryType.startsWith(include))
continue;
if (!exclude.isEmpty() && primaryType.startsWith(exclude))
continue;
if (subTypesMap.containsKey(primaryType))
toSetList.add(iterateNodeAttributeFields(subTypesMap.get(primaryType), currentNode));
else toSetList.add(iterateNodeAttributeFields(listType, currentNode));
}
if (toSetList.size()!=0) field.set(obj, toSetList);
}
}
return obj;
}
private <T> void setMapAttribute(Field field, T instance, Node node) throws Exception{
field.setAccessible(true);
String exclude = field.getAnnotation(MapAttribute.class).excludeStartWith();
Map<String, Object> mapToset = new HashMap<String, Object>();
PropertyIterator iterator = node.getProperties();
if (iterator!=null) {
while (iterator.hasNext()){
Property prop = iterator.nextProperty();
if (!exclude.isEmpty() && prop.getName().startsWith(exclude)) continue;
try{
logger.trace("adding {} in the map",prop.getName());
mapToset.put(prop.getName(), getPropertyValue(prop));
}catch(PathNotFoundException e){
logger.warn("the property {} is not mapped",prop.getName());
} catch (Exception e ) {
logger.trace("error setting value {}",e);
}
}
}
field.set(instance, mapToset);
}
@SuppressWarnings("unchecked")
private <T> void setListNode(Field field, T instance, Node node) throws Exception{
field.setAccessible(true);
String exclude = field.getAnnotation(ListNodes.class).excludeTypeStartWith();
String include = field.getAnnotation(ListNodes.class).includeTypeStartWith();
Class listType = field.getAnnotation(ListNodes.class).listClass();
Map<String, Class> subTypesMap = Collections.emptyMap();
if (!typeToSubtypeMap.containsKey(listType)) {
Configuration config = new ConfigurationBuilder().forPackages(listType.getPackage().getName());
Reflections reflections = new Reflections(config);
Set<Class> subTypes = reflections.getSubTypesOf(listType);
if (subTypes.size()>0) {
subTypesMap = new HashMap<>();
for (Class subtype: subTypes)
if (subtype.isAnnotationPresent(AttributeRootNode.class)) {
AttributeRootNode attributeRootNode = (AttributeRootNode)subtype.getAnnotation(AttributeRootNode.class);
subTypesMap.put(attributeRootNode.value(), subtype);
}
} else logger.trace("no subtypes found for {}",listType.getName());
typeToSubtypeMap.put(listType, subTypesMap);
} else {
logger.debug("subtypes already found in cache");
subTypesMap = typeToSubtypeMap.get(listType);
}
List<Object> toSetList = new ArrayList<>();
NodeIterator iterator = node.getNodes();
while (iterator.hasNext()){
Node currentNode = iterator.nextNode();
String primaryType = currentNode.getPrimaryNodeType().getName();
logger.trace("the current node {} has a list",currentNode.getName());
if (!include.isEmpty() && !primaryType.startsWith(include))
continue;
if (!exclude.isEmpty() && primaryType.startsWith(exclude))
continue;
if (subTypesMap.containsKey(primaryType))
toSetList.add(iterateNodeAttributeFields(subTypesMap.get(primaryType), currentNode));
else toSetList.add(iterateNodeAttributeFields(listType, currentNode));
}
if (toSetList.size()!=0) field.set(instance, toSetList);
}
private <T> void setAttributeFieldCheckingDefault(Field field, T instance, Node node) {
Attribute attribute = field.getAnnotation(Attribute.class);
field.setAccessible(true);
try{
Object propValue;
Class<?> returnType = field.getType();
if (node.hasProperty(attribute.value())) {
propValue = getPropertyValue(returnType, node.getProperty(attribute.value()));
if (!attribute.defaultValue().isEmpty() && propValue==null )
propValue = returnType.cast(attribute.defaultValue());
field.set(instance, propValue);
logger.trace("retrieve item - added field {}",field.getName());
} else if (!attribute.defaultValue().isEmpty()){
propValue = returnType.cast(attribute.defaultValue());
field.set(instance, propValue);
logger.trace("retrieve item - setting default for field {}",field.getName());
} else
logger.trace("property not found for field {}",field.getName());
} catch (Exception e ) {
logger.debug("error setting value for property {} ",attribute.value());
}
}
@SuppressWarnings({ "unchecked" })
private Object getPropertyValue(Class returnType, Property prop) throws Exception{
if (returnType.equals(String.class)) return prop.getString();

View File

@ -28,7 +28,7 @@ public class ArchiveStructureCreationParameter extends CreateParameters {
@Override
protected boolean isValid() {
return Objects.nonNull(parentFolderName) && Objects.nonNull(stream) && Objects.nonNull(fileDetails);
return Objects.nonNull(parentFolderName) && Objects.nonNull(stream);
}
@Override

View File

@ -1,16 +1,18 @@
package org.gcube.data.access.storagehub.handlers.items.builders;
import java.util.Map;
import java.util.Objects;
import org.gcube.common.storagehub.model.plugins.PluginParameters;
import org.gcube.common.storagehub.model.Metadata;
import org.gcube.common.storagehub.model.items.nodes.PayloadBackend;
public class FolderCreationParameters extends CreateParameters {
private String name;
private String description="";
private boolean hidden = false;
private String externalPluginName = null;
private PluginParameters externalPluginParameters = null;
private PayloadBackend backend;
protected FolderCreationParameters() {}
@ -26,16 +28,8 @@ public class FolderCreationParameters extends CreateParameters {
return hidden;
}
public boolean isExternal() {
return externalPluginName!=null;
}
public String getPluginName(String name) {
return this.externalPluginName;
}
public PluginParameters getPluginParameters() {
return externalPluginParameters;
public PayloadBackend getBackend() {
return backend;
}
@Override
@ -70,8 +64,8 @@ public class FolderCreationParameters extends CreateParameters {
return this;
}
public ExternalFolderCreationBuilder onRepository(String pluginName) {
return new ExternalFolderCreationBuilder(pluginName, this);
public BackendCreationBuilder onRepository(String pluginName) {
return new BackendCreationBuilder(pluginName, this);
}
public FolderCreationBuilder hidden(boolean hidden) {
@ -81,19 +75,26 @@ public class FolderCreationParameters extends CreateParameters {
}
public static class ExternalFolderCreationBuilder {
public static class BackendCreationBuilder {
FolderCreationBuilder cb;
protected ExternalFolderCreationBuilder(String pluginName, FolderCreationBuilder cb) {
this.cb.parameters.externalPluginName = pluginName;
String plugin;
protected BackendCreationBuilder(String pluginName, FolderCreationBuilder cb) {
this.cb = cb;
this.plugin = pluginName;
}
public FolderCreationBuilder withParameters(PluginParameters params){
this.cb.parameters.externalPluginParameters = params;
public FolderCreationBuilder withParameters(Map<String,Object> params){
this.cb.parameters.backend = new PayloadBackend(plugin, new Metadata(params));
return this.cb;
}
public FolderCreationBuilder withoutParameters(){
this.cb.parameters.backend = new PayloadBackend(plugin, null);
return this.cb;
}
}

View File

@ -1,80 +0,0 @@
package org.gcube.data.access.storagehub.handlers.plugins;
import java.util.Collections;
import java.util.Map;
import java.util.stream.Collectors;
import javax.enterprise.inject.Default;
import javax.enterprise.inject.Instance;
import javax.inject.Inject;
import javax.inject.Singleton;
import javax.jcr.Node;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import org.gcube.common.storagehub.model.Excludes;
import org.gcube.common.storagehub.model.exceptions.BackendGenericError;
import org.gcube.common.storagehub.model.exceptions.PluginInitializationException;
import org.gcube.common.storagehub.model.exceptions.PluginNotFoundException;
import org.gcube.common.storagehub.model.items.ExternalFolder;
import org.gcube.common.storagehub.model.items.Item;
import org.gcube.common.storagehub.model.plugins.FolderManager;
import org.gcube.common.storagehub.model.plugins.FolderManagerConnector;
import org.gcube.data.access.storagehub.handlers.items.Node2ItemConverter;
import org.gcube.data.access.storagehub.storage.backend.impl.GcubeFolderManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@Singleton
public class FolderPluginHandler {
private static Logger log = LoggerFactory.getLogger(FolderPluginHandler.class);
@Inject
Node2ItemConverter node2Item;
private GcubeFolderManager defaultManager = new GcubeFolderManager();
public FolderManager getDefault() {
return defaultManager;
}
@Inject
Instance<FolderManagerConnector> connectors;
private Map<String, FolderManagerConnector> connectorsMap;
FolderPluginHandler(){
if (connectors !=null)
connectorsMap = connectors.stream().collect(Collectors.toMap(FolderManagerConnector::getName, e -> e ));
else {
log.info("connectors are null");
connectorsMap = Collections.emptyMap();
}
}
public FolderManagerConnector getConnector(String name) throws PluginNotFoundException {
if (!connectorsMap.containsKey(name)) throw new PluginNotFoundException("plugin "+name+" not found");
return connectorsMap.get(name);
}
public FolderManager getFolderManager(Item item) throws PluginInitializationException, PluginNotFoundException, RepositoryException, BackendGenericError{
if (!item.isExternalManaged())
return defaultManager;
Session session = ((Node)item.getRelatedNode()).getSession();
Item parent = null;
do {
String parentId = item.getParentId();
Node node = session.getNodeByIdentifier(parentId);
parent = node2Item.getItem(node, Excludes.ALL);
if (parent !=null && parent instanceof ExternalFolder) {
ExternalFolder extParent = (ExternalFolder) parent;
String plugin = extParent.getManagedBy();
Map<String, Object> parameters = extParent.getConnectionParameters().getMap();
return getConnector(plugin).connect(extParent, parameters);
}
} while (parent!=null);
throw new BackendGenericError("selected external managed item doesn't have a parent external folder");
}
}

View File

@ -1,28 +0,0 @@
package org.gcube.data.access.storagehub.handlers.plugins;
import javax.inject.Inject;
import javax.inject.Singleton;
@Singleton
public class OperationMediator {
@Inject
FolderPluginHandler folderHandler;
/*
boolean onMove(Item source, Item destination, Session session) throws PluginInitializationException, PluginNotFoundException, BackendGenericError, RepositoryException{
FolderManager sourceFolderManager = folderHandler.getFolderManager(source);
FolderManager destinationFolderManager = folderHandler.getFolderManager(destination);
if (source instanceof FolderItem) {
destinationFolderManager.onCreatedFolder((FolderItem) source);
session.move(source.getPath(), destination.getPath());
sourceFolderManager.onDeletingFolder((FolderItem) source);
} else if (source instanceof AbstractFileItem){
}
}
*/
}

View File

@ -0,0 +1,60 @@
package org.gcube.data.access.storagehub.handlers.plugins;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import jakarta.annotation.PostConstruct;
import jakarta.enterprise.inject.Instance;
import jakarta.inject.Inject;
import jakarta.inject.Singleton;
import org.gcube.common.storagehub.model.Constants;
import org.gcube.common.storagehub.model.exceptions.PluginNotFoundException;
import org.gcube.common.storagehub.model.items.nodes.PayloadBackend;
import org.gcube.common.storagehub.model.storages.StorageBackendFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@Singleton
public class StorageBackendHandler {
private static Logger log = LoggerFactory.getLogger(StorageBackendHandler.class);
public static PayloadBackend getDefaultPayloadForFolder() {
return new PayloadBackend(Constants.DEFAULT_S3_STORAGE, null);
}
@Inject
Instance<StorageBackendFactory> factories;
Map<String, StorageBackendFactory> storagebackendMap= new HashMap<String, StorageBackendFactory>();
@PostConstruct
void init(){
if (factories !=null)
for (StorageBackendFactory connector : factories) {
if (storagebackendMap.containsKey(connector.getName())) {
log.error("multiple storage backend with the same name");
throw new RuntimeException("multiple storage backend with the same name");
}
storagebackendMap.put(connector.getName(), connector);
}
else
throw new RuntimeException("storage backend implementation not found");
}
public StorageBackendFactory get(PayloadBackend payload) throws PluginNotFoundException {
if (payload == null || !storagebackendMap.containsKey(payload.getStorageName()))
throw new PluginNotFoundException(String.format("implementation for storage %s not found", payload.getStorageName()));
return storagebackendMap.get(payload.getStorageName());
}
public StorageBackendFactory get(String storageName) throws PluginNotFoundException {
return storagebackendMap.get(storageName);
}
public Collection<StorageBackendFactory> getAllImplementations() {
return storagebackendMap.values();
}
}

View File

@ -0,0 +1,50 @@
package org.gcube.data.access.storagehub.handlers.plugins;
import java.io.InputStream;
import jakarta.inject.Inject;
import jakarta.inject.Singleton;
import org.gcube.common.storagehub.model.exceptions.StorageHubException;
import org.gcube.common.storagehub.model.items.nodes.Content;
import org.gcube.common.storagehub.model.items.nodes.PayloadBackend;
import org.gcube.common.storagehub.model.storages.MetaInfo;
import org.gcube.common.storagehub.model.storages.StorageBackend;
import org.gcube.common.storagehub.model.storages.StorageBackendFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@Singleton
public class StorageOperationMediator {
Logger log = LoggerFactory.getLogger(StorageOperationMediator.class);
@Inject
StorageBackendHandler storageBackendHandler;
public MetaInfo copy(Content source, PayloadBackend destination, String newName, String newParentPath, String login) throws StorageHubException{
log.info("creating Storages for source {} and destination {}", source.getPayloadBackend(), destination.getStorageName());
StorageBackendFactory sourceSBF = storageBackendHandler.get(source.getPayloadBackend());
//TODO: add metadata taken from content node
StorageBackend sourceSB = sourceSBF.create(source.getPayloadBackend());
StorageBackendFactory destSBF = storageBackendHandler.get(destination);
StorageBackend destSB = destSBF.create(destination);
if (sourceSB.equals(destSB)) {
log.info("source and destintiona are the same storage");
return sourceSB.onCopy(source, newParentPath, newName);
}else {
log.info("source and destintiona are different storage");
InputStream stream = sourceSB.download(source);
MetaInfo info = destSB.upload(stream, newParentPath, newName, source.getSize(), login);
return info;
}
}
public boolean move(){
return true;
}
}

View File

@ -6,32 +6,32 @@ import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import javax.inject.Inject;
import javax.inject.Singleton;
import javax.jcr.Node;
import javax.jcr.RepositoryException;
import javax.jcr.SimpleCredentials;
import javax.servlet.ServletContext;
import org.apache.jackrabbit.api.JackrabbitSession;
import org.apache.jackrabbit.api.security.user.Group;
import org.apache.jackrabbit.api.security.user.User;
import org.apache.jackrabbit.api.security.user.UserManager;
import org.gcube.common.scope.api.ScopeProvider;
import org.gcube.common.scope.impl.ScopeBean;
import org.gcube.common.scope.impl.ScopeBean.Type;
import org.gcube.common.security.ContextBean;
import org.gcube.common.security.ContextBean.Type;
import org.gcube.common.security.providers.SecretManagerProvider;
import org.gcube.common.security.secrets.Secret;
import org.gcube.common.storagehub.model.exceptions.BackendGenericError;
import org.gcube.common.storagehub.model.exceptions.InvalidCallParameters;
import org.gcube.common.storagehub.model.exceptions.StorageHubException;
import org.gcube.common.storagehub.model.items.Item;
import org.gcube.data.access.storagehub.Constants;
import org.gcube.data.access.storagehub.PathUtil;
import org.gcube.data.access.storagehub.handlers.GroupHandler;
import org.gcube.data.access.storagehub.handlers.items.Node2ItemConverter;
import org.gcube.data.access.storagehub.services.RepositoryInitializer;
import org.gcube.data.access.storagehub.repository.StoragehubRepository;
import org.gcube.data.access.storagehub.services.delegates.GroupManagerDelegate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import jakarta.inject.Inject;
import jakarta.inject.Singleton;
@Singleton
public class VREManager {
@ -39,8 +39,7 @@ public class VREManager {
private Map<String, VRE> vreMap = new HashMap<>();
@Inject
RepositoryInitializer repository;
StoragehubRepository repository = StoragehubRepository.repository;
@Inject
Node2ItemConverter node2Item;
@ -49,18 +48,11 @@ public class VREManager {
PathUtil pathUtil;
@Inject
GroupHandler groupHandler;
GroupManagerDelegate groupHandler;
ExecutorService executor = Executors.newFixedThreadPool(5);
SimpleCredentials credentials;
@Inject
public VREManager(ServletContext context) {
credentials = new SimpleCredentials(context.getInitParameter(Constants.ADMIN_PARAM_NAME),context.getInitParameter(Constants.ADMIN_PARAM_PWD).toCharArray());
}
public synchronized VRE getVRE(String completeName) {
logger.trace("requesting VRE {}",completeName);
if (vreMap.containsKey(completeName))
@ -74,7 +66,7 @@ public class VREManager {
logger.trace("inserting VRE {}",vreFolder.getTitle());
if (vreMap.containsKey(vreFolder.getTitle())) throw new RuntimeException("something went wrong (vre already present in the map)");
else {
VRE toReturn = new VRE(vreFolder, repository.getRepository(), credentials, node2Item, executor);
VRE toReturn = new VRE(vreFolder, repository.getRepository(), Constants.JCR_CREDENTIALS, node2Item, executor);
vreMap.put(vreFolder.getTitle(), toReturn);
return toReturn;
}
@ -82,7 +74,8 @@ public class VREManager {
}
public synchronized VRE getVreFolderItem(JackrabbitSession ses, String userId, List<String> excludes ) throws RepositoryException, StorageHubException{
ScopeBean bean = new ScopeBean(ScopeProvider.instance.get());
Secret secret = SecretManagerProvider.get();
ContextBean bean = new ContextBean(secret.getContext());
if (!bean.is(Type.VRE)) throw new BackendGenericError("the current scope is not a VRE");
String entireScopeName= bean.toString().replaceAll("^/(.*)/?$", "$1").replaceAll("/", "-");
return getVreFolderItemByGroupName(ses, entireScopeName, userId, excludes);

View File

@ -0,0 +1,41 @@
package org.gcube.data.access.storagehub.health;
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.common.storagehub.model.items.nodes.PayloadBackend;
import org.gcube.data.access.storagehub.handlers.plugins.StorageBackendHandler;
import org.gcube.data.access.storagehub.storage.backend.impl.GcubeDefaultS3StorageBackendFactory;
import org.gcube.data.access.storagehub.storage.backend.impl.S3Backend;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ReadinessChecker
public class DefaultStorageCheck implements HealthCheck{
private static Logger log = LoggerFactory.getLogger(DefaultStorageCheck.class);
PayloadBackend defaultPayload = StorageBackendHandler.getDefaultPayloadForFolder();
@Override
public String getName() {
return String.format("default storage (%s)",defaultPayload.getStorageName());
}
@Override
public HealthCheckResponse check() {
try {
GcubeDefaultS3StorageBackendFactory storageFactory =new GcubeDefaultS3StorageBackendFactory();
storageFactory.init();
if (((S3Backend)storageFactory.create(defaultPayload)).isAlive())
return HealthCheckResponse.builder(getName()).up().build();
else
return HealthCheckResponse.builder(getName()).down().error("error contacting storage").build();
} catch (Exception e) {
log.error("error checking defaultStorage",e);
return HealthCheckResponse.builder(getName()).down().error(e.getMessage()).build();
}
}
}

View File

@ -0,0 +1,35 @@
package org.gcube.data.access.storagehub.health;
import javax.jcr.LoginException;
import javax.jcr.Session;
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.data.access.storagehub.repository.StoragehubRepository;
@ReadinessChecker
public class JCRRepositoryCheck implements HealthCheck{
StoragehubRepository repository = StoragehubRepository.repository;
@Override
public String getName() {
return "Jackrabbit repository";
}
@Override
public HealthCheckResponse check() {
try {
Session session = repository.getRepository().login();
if (session != null) session.logout();
return HealthCheckResponse.builder(getName()).up().build();
}catch (LoginException e) { }
catch(Throwable ex) {
return HealthCheckResponse.builder(getName()).down().error(ex.getMessage()).build();
}
return HealthCheckResponse.builder(getName()).up().build();
}
}

View File

@ -1,6 +1,6 @@
package org.gcube.data.access.storagehub.query.sql2.evaluators;
import javax.inject.Singleton;
import jakarta.inject.Singleton;
import org.gcube.common.storagehub.model.expressions.Expression;

View File

@ -1,8 +1,8 @@
package org.gcube.data.access.storagehub.query.sql2.evaluators;
import javax.enterprise.inject.Instance;
import javax.inject.Inject;
import javax.inject.Singleton;
import jakarta.enterprise.inject.Instance;
import jakarta.inject.Inject;
import jakarta.inject.Singleton;
import org.gcube.common.storagehub.model.expressions.Expression;
@ -19,6 +19,7 @@ public class Evaluators {
@Inject
Instance<Evaluator<?>> evaluators;
@SuppressWarnings({ "rawtypes", "unchecked" })
public String evaluate(Expression<?> expression) {
for (Evaluator eval: evaluators) {
if (eval.getType().equals(expression.getClass()))

View File

@ -5,7 +5,7 @@ import java.text.SimpleDateFormat;
import java.util.List;
import java.util.TimeZone;
import javax.inject.Singleton;
import jakarta.inject.Singleton;
import org.gcube.common.storagehub.model.expressions.Expression;
import org.gcube.common.storagehub.model.expressions.date.Before;

View File

@ -4,7 +4,7 @@ import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import javax.inject.Singleton;
import jakarta.inject.Singleton;
import org.gcube.common.storagehub.model.expressions.Expression;
import org.gcube.common.storagehub.model.expressions.logical.And;

View File

@ -1,6 +1,6 @@
package org.gcube.data.access.storagehub.query.sql2.evaluators.logical;
import javax.inject.Singleton;
import jakarta.inject.Singleton;
import org.gcube.common.storagehub.model.expressions.Expression;
import org.gcube.common.storagehub.model.expressions.logical.ISDescendant;

View File

@ -4,7 +4,7 @@ import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import javax.inject.Singleton;
import jakarta.inject.Singleton;
import org.gcube.common.storagehub.model.expressions.Expression;
import org.gcube.common.storagehub.model.expressions.logical.Or;

View File

@ -1,6 +1,6 @@
package org.gcube.data.access.storagehub.query.sql2.evaluators.text;
import javax.inject.Singleton;
import jakarta.inject.Singleton;
import org.gcube.common.storagehub.model.expressions.Expression;
import org.gcube.common.storagehub.model.expressions.text.Contains;

View File

@ -0,0 +1,111 @@
package org.gcube.data.access.storagehub.repository;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.Charset;
import javax.jcr.Repository;
import javax.jcr.Session;
import javax.jcr.nodetype.NodeType;
import javax.naming.Context;
import javax.naming.InitialContext;
import org.apache.jackrabbit.api.JackrabbitRepository;
import org.apache.jackrabbit.api.JackrabbitSession;
import org.apache.jackrabbit.api.JackrabbitWorkspace;
import org.apache.jackrabbit.api.security.authorization.PrivilegeManager;
import org.apache.jackrabbit.commons.cnd.CndImporter;
import org.gcube.data.access.storagehub.Constants;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import jakarta.enterprise.context.ApplicationScoped;
@ApplicationScoped
public class JackrabbitRepositoryImpl implements StoragehubRepository {
private static final Logger log = LoggerFactory.getLogger(JackrabbitRepositoryImpl.class);
private Repository repository;
public JackrabbitRepositoryImpl(){
try {
InitialContext context = new InitialContext();
Context environment = (Context) context.lookup("java:comp/env");
repository = (Repository) environment.lookup("jcr/repository");
}catch (Throwable e) {
log.error("error initializing repository", e);
throw new RuntimeException("error initializing repository",e);
}
}
@Override
public Repository getRepository() {
return repository;
}
private boolean jackrabbitInitialized = false;
@Override
public synchronized void initContainerAtFirstStart() {
try {
JackrabbitSession ses = (JackrabbitSession) this.repository.login(Constants.JCR_CREDENTIALS);
try {
boolean notAlreadyDone = !jackrabbitInitialized && !ses.getRootNode().hasNode("Home");
if (notAlreadyDone)
this.init(ses);
else log.info("jackrabbit is already initialized");
}finally {
ses.logout();
}
} catch (Exception e) {
log.warn("error initialising Jackrabbit",e);
}
jackrabbitInitialized = true;
}
@Override
public void shutdown() {
((JackrabbitRepository)repository).shutdown();
}
public void init(JackrabbitSession ses) throws Exception{
log.info("init started");
try {
initNodeTypes(ses);
ses.getRootNode().addNode("Home");
ses.getRootNode().addNode("Share");
PrivilegeManager pm = ((JackrabbitWorkspace) ses.getWorkspace()).getPrivilegeManager();
pm.registerPrivilege("hl:writeAll", false, new String[0]);
ses.save();
}catch (Exception e) {
log.error("init error", e);
throw e;
}
log.info("init finished");
}
void initNodeTypes(Session ses) throws Exception{
InputStream stream = this.getClass().getResourceAsStream("/init/NodeType.cnd");
if (stream == null)
throw new Exception("NodeType.cnd inputStream is null");
InputStreamReader inputstream = new InputStreamReader(stream, Charset.forName("UTF-8"));
// Register the custom node types defined in the CND file, using JCR Commons CndImporter
log.info("start to register the custom node types defined in the CND file...");
NodeType[] nodeTypes = CndImporter.registerNodeTypes(inputstream, ses, true);
for (NodeType nt : nodeTypes)
log.info("Registered: {} ", nt.getName());
log.info("custom node types registered");
}
}

View File

@ -0,0 +1,14 @@
package org.gcube.data.access.storagehub.repository;
import javax.jcr.Repository;
public interface StoragehubRepository {
static final StoragehubRepository repository = new JackrabbitRepositoryImpl();
Repository getRepository();
void shutdown();
void initContainerAtFirstStart();
}

View File

@ -2,24 +2,10 @@ package org.gcube.data.access.storagehub.services;
import java.util.Collections;
import javax.enterprise.context.RequestScoped;
import javax.inject.Inject;
import javax.jcr.Node;
import javax.jcr.NodeIterator;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.servlet.ServletContext;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import org.gcube.common.gxrest.response.outbound.GXOutboundErrorResponse;
import org.gcube.common.storagehub.model.Excludes;
@ -35,11 +21,13 @@ import org.gcube.common.storagehub.model.items.SharedFolder;
import org.gcube.common.storagehub.model.items.VreFolder;
import org.gcube.common.storagehub.model.types.ACLList;
import org.gcube.data.access.storagehub.AuthorizationChecker;
import org.gcube.data.access.storagehub.Constants;
import org.gcube.data.access.storagehub.PathUtil;
import org.gcube.data.access.storagehub.StorageHubAppllicationManager;
import org.gcube.data.access.storagehub.handlers.CredentialHandler;
import org.gcube.data.access.storagehub.StorageHubApplicationManager;
import org.gcube.data.access.storagehub.handlers.ACLHandler;
import org.gcube.data.access.storagehub.handlers.UnshareHandler;
import org.gcube.data.access.storagehub.handlers.items.Node2ItemConverter;
import org.gcube.data.access.storagehub.repository.StoragehubRepository;
import org.gcube.data.access.storagehub.services.interfaces.ACLManagerInterface;
import org.gcube.smartgears.annotations.ManagedBy;
import org.gcube.smartgears.utils.InnerMethodName;
@ -47,33 +35,59 @@ import org.glassfish.jersey.media.multipart.FormDataParam;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.webcohesion.enunciate.metadata.rs.RequestHeader;
import com.webcohesion.enunciate.metadata.rs.RequestHeaders;
import jakarta.enterprise.context.RequestScoped;
import jakarta.inject.Inject;
import jakarta.servlet.ServletContext;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.DELETE;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.PUT;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.WebApplicationException;
import jakarta.ws.rs.core.Context;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
@Path("items")
@ManagedBy(StorageHubAppllicationManager.class)
@ManagedBy(StorageHubApplicationManager.class)
@RequestHeaders({
@RequestHeader( name = "Authorization", description = "Bearer token, see https://dev.d4science.org/how-to-access-resources"),
})
public class ACLManager extends Impersonable {
private static final Logger log = LoggerFactory.getLogger(ACLManager.class);
RepositoryInitializer repository = StorageHubAppllicationManager.repository;
StoragehubRepository repository = StoragehubRepository.repository;
@Inject
ACLHandler aclHandler;
@RequestScoped
@PathParam("id")
String id;
@Inject
AuthorizationChecker authChecker;
@Inject
PathUtil pathUtil;
@Context
ServletContext context;
@Inject Node2ItemConverter node2Item;
@Inject UnshareHandler unshareHandler;
@Inject ACLManagerInterface aclManagerDelegate;
/**
* returns the AccessType for all the users in a shared folder
*
@ -84,10 +98,10 @@ public class ACLManager extends Impersonable {
@Path("{id}/acls")
@Produces(MediaType.APPLICATION_JSON)
public ACLList getACL() {
InnerMethodName.instance.set("getACLById");
InnerMethodName.set("getACLById");
Session ses = null;
try{
ses = repository.getRepository().login(CredentialHandler.getAdminCredentials(context));
ses = repository.getRepository().login(Constants.JCR_CREDENTIALS);
Item item = node2Item.getItem(ses.getNodeByIdentifier(id), Excludes.ALL);
authChecker.checkReadAuthorizationControl(ses, currentUser, id);
return new ACLList(aclManagerDelegate.get(item, ses));
@ -121,13 +135,13 @@ public class ACLManager extends Impersonable {
@Consumes(MediaType.MULTIPART_FORM_DATA)
@Path("{id}/acls")
public void updateACL(@FormDataParam("user") String user, @FormDataParam("access") AccessType accessType) {
InnerMethodName.instance.set("setACLById");
InnerMethodName.set("setACLById");
Session ses = null;
try {
if (user==currentUser) throw new InvalidCallParameters("own ACLs cannot be modified");
ses = repository.getRepository().login(CredentialHandler.getAdminCredentials(context));
ses = repository.getRepository().login(Constants.JCR_CREDENTIALS);
Node node = ses.getNodeByIdentifier(id);
Item item = node2Item.getItem(node, Excludes.ALL);
@ -139,28 +153,25 @@ public class ACLManager extends Impersonable {
throw new UserNotAuthorizedException("owner acl cannot be changed");
SharedFolder folder = (SharedFolder) item;
authChecker.checkAdministratorControl(ses, currentUser, folder);
if (folder.isVreFolder()) {
if (accessType==AccessType.ADMINISTRATOR) throw new InvalidCallParameters("a VRE admin cannot be changed with this method");
if (!user.equals(folder.getTitle())) throw new InvalidCallParameters("the groupId in the argument is different to the one of the VREFolder");
if (item instanceof VreFolder || folder.isVreFolder())
throw new InvalidCallParameters("acls in vreFolder cannot be updated with this method");
} else {
NodeIterator sharedSet = node.getSharedSet();
boolean found = false;
while (sharedSet.hasNext() && !found) {
Node current = sharedSet.nextNode();
if (current.getPath().startsWith(pathUtil.getWorkspacePath(user).toPath()))
found = true;
}
if (!found)
throw new InvalidCallParameters("shared folder with id "+folder.getId()+" is not shared with user "+user);
NodeIterator sharedSet = node.getSharedSet();
boolean found = false;
while (sharedSet.hasNext() && !found) {
Node current = sharedSet.nextNode();
if (current.getPath().startsWith(pathUtil.getWorkspacePath(user).toPath()))
found = true;
}
aclManagerDelegate.update(user, folder, accessType, ses);
if (!found)
throw new InvalidCallParameters("shared folder with id "+folder.getId()+" is not shared with user "+user);
aclManagerDelegate.update(user, node, accessType, ses);
}catch(RepositoryException re){
log.error("jcr error extracting archive", re);
throw new WebApplicationException(new BackendGenericError("jcr error setting acl", re));
@ -191,21 +202,21 @@ public class ACLManager extends Impersonable {
@Consumes(MediaType.TEXT_PLAIN)
@Path("{id}/acls/{user}")
public void removeACL(@PathParam("user") String user) {
InnerMethodName.instance.set("removeACLById");
InnerMethodName.set("removeACLById");
Session ses = null;
try{
ses = repository.getRepository().login(CredentialHandler.getAdminCredentials(context));
ses = repository.getRepository().login(Constants.JCR_CREDENTIALS);
Node node = ses.getNodeByIdentifier(id);
Item item = node2Item.getItem(node, Excludes.ALL);
if (!(item instanceof SharedFolder))
throw new InvalidItemException("the item is not a shared folder");
if (item instanceof VreFolder || ((SharedFolder) item).isVreFolder())
throw new InvalidCallParameters("acls in vreFolder cannot be removed with this method");
authChecker.checkAdministratorControl(ses, currentUser, (SharedFolder) item);
unshareHandler.unshare(ses, Collections.singleton(user), node, currentUser);
@ -225,11 +236,11 @@ public class ACLManager extends Impersonable {
@GET
@Path("{id}/acls/write")
public Boolean canWriteInto() {
InnerMethodName.instance.set("canWriteIntoFolder");
InnerMethodName.set("canWriteIntoFolder");
Session ses = null;
Boolean canWrite = false;
try{
ses = repository.getRepository().login(CredentialHandler.getAdminCredentials(context));
ses = repository.getRepository().login(Constants.JCR_CREDENTIALS);
Node node = ses.getNodeByIdentifier(id);
Item item = node2Item.getItem(node, Excludes.ALL);
if (!(item instanceof FolderItem))

View File

@ -0,0 +1,49 @@
package org.gcube.data.access.storagehub.services;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.WebApplicationException;
import jakarta.ws.rs.core.Context;
import jakarta.ws.rs.core.Response.Status;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@Path("api-docs")
public class DocsGenerator {
private static Logger logger = LoggerFactory.getLogger(DocsGenerator.class);
@GET
@Path("/{any: .*}")
public InputStream toDoc(@Context HttpServletRequest req) throws WebApplicationException {
logger.info(DocsGenerator.class.getSimpleName() + " toDoc called");
String pathInfo = req.getPathInfo();
logger.debug("pathInfo {}", pathInfo);
try {
if (pathInfo.endsWith("/api-docs")) {
pathInfo += "index.html";
}
if (pathInfo.endsWith("/api-docs/")) {
pathInfo += "index.html";
}
logger.info("going to {}", pathInfo);
String realPath = req.getServletContext().getRealPath(pathInfo);
return new FileInputStream(new File(realPath));
} catch (Exception e) {
logger.error("error getting the docs", e);
throw new WebApplicationException(e,Status.SERVICE_UNAVAILABLE);
}
}
}

View File

@ -3,132 +3,80 @@ package org.gcube.data.access.storagehub.services;
import static org.gcube.data.access.storagehub.Roles.INFRASTRUCTURE_MANAGER_ROLE;
import static org.gcube.data.access.storagehub.Roles.VREMANAGER_ROLE;
import java.security.Principal;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Objects;
import javax.inject.Inject;
import javax.jcr.Node;
import javax.jcr.PathNotFoundException;
import javax.jcr.RepositoryException;
import javax.jcr.security.AccessControlEntry;
import javax.jcr.security.AccessControlManager;
import javax.jcr.security.Privilege;
import javax.servlet.ServletContext;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.FormParam;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import org.apache.jackrabbit.api.JackrabbitSession;
import org.apache.jackrabbit.api.security.JackrabbitAccessControlList;
import org.apache.jackrabbit.api.security.user.Authorizable;
import org.apache.jackrabbit.api.security.user.Group;
import org.apache.jackrabbit.api.security.user.Query;
import org.apache.jackrabbit.api.security.user.QueryBuilder;
import org.apache.jackrabbit.api.security.user.User;
import org.apache.jackrabbit.commons.jackrabbit.authorization.AccessControlUtils;
import org.gcube.common.authorization.control.annotations.AuthorizationControl;
import org.gcube.common.authorization.library.provider.AuthorizationProvider;
import org.gcube.common.gxrest.response.outbound.GXOutboundErrorResponse;
import org.gcube.common.scope.api.ScopeProvider;
import org.gcube.common.scope.impl.ScopeBean;
import org.gcube.common.scope.impl.ScopeBean.Type;
import org.gcube.common.storagehub.model.Excludes;
import org.gcube.common.storagehub.model.Paths;
import org.gcube.common.security.providers.SecretManagerProvider;
import org.gcube.common.storagehub.model.acls.AccessType;
import org.gcube.common.storagehub.model.exceptions.BackendGenericError;
import org.gcube.common.storagehub.model.exceptions.InvalidCallParameters;
import org.gcube.common.storagehub.model.exceptions.StorageHubException;
import org.gcube.common.storagehub.model.exceptions.UserNotAuthorizedException;
import org.gcube.common.storagehub.model.items.Item;
import org.gcube.common.storagehub.model.types.NodeProperty;
import org.gcube.common.storagehub.model.types.PrimaryNodeType;
import org.gcube.data.access.storagehub.AuthorizationChecker;
import org.gcube.data.access.storagehub.Constants;
import org.gcube.data.access.storagehub.PathUtil;
import org.gcube.data.access.storagehub.StorageHubAppllicationManager;
import org.gcube.data.access.storagehub.Utils;
import org.gcube.data.access.storagehub.exception.MyAuthException;
import org.gcube.data.access.storagehub.handlers.CredentialHandler;
import org.gcube.data.access.storagehub.handlers.GroupHandler;
import org.gcube.data.access.storagehub.handlers.TrashHandler;
import org.gcube.data.access.storagehub.handlers.items.Node2ItemConverter;
import org.gcube.data.access.storagehub.handlers.items.builders.FolderCreationParameters;
import org.gcube.data.access.storagehub.handlers.vres.VRE;
import org.gcube.data.access.storagehub.handlers.vres.VREManager;
import org.gcube.data.access.storagehub.StorageHubApplicationManager;
import org.gcube.data.access.storagehub.repository.StoragehubRepository;
import org.gcube.data.access.storagehub.services.delegates.GroupManagerDelegate;
import org.gcube.smartgears.annotations.ManagedBy;
import org.gcube.smartgears.utils.InnerMethodName;
import org.glassfish.jersey.media.multipart.FormDataParam;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.webcohesion.enunciate.metadata.rs.RequestHeader;
import com.webcohesion.enunciate.metadata.rs.RequestHeaders;
import jakarta.inject.Inject;
import jakarta.inject.Singleton;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.DELETE;
import jakarta.ws.rs.DefaultValue;
import jakarta.ws.rs.FormParam;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.PUT;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
@Path("groups")
@ManagedBy(StorageHubAppllicationManager.class)
@Singleton
@ManagedBy(StorageHubApplicationManager.class)
@RequestHeaders({
@RequestHeader( name = "Authorization", description = "Bearer token, see https://dev.d4science.org/how-to-access-resources"),
})
public class GroupManager {
@Context ServletContext context;
@Inject
TrashHandler trashHandler;
private static final Logger log = LoggerFactory.getLogger(GroupManager.class);
RepositoryInitializer repository = StorageHubAppllicationManager.repository;
@Inject
VREManager vreManager;
@Inject
GroupHandler groupHandler;
private final StoragehubRepository repository = StoragehubRepository.repository;
@Inject
Node2ItemConverter node2Item;
@Inject
GroupManagerDelegate groupHandler;
@Inject
PathUtil pathUtil;
@Inject
AuthorizationChecker authChecker;
@GET
@Path("")
@Produces(MediaType.APPLICATION_JSON)
public List<String> getGroups(){
InnerMethodName.instance.set("getGroups");
InnerMethodName.set("getGroups");
JackrabbitSession session = null;
List<String> groups= new ArrayList<>();
try {
session = (JackrabbitSession) repository.getRepository().login(CredentialHandler.getAdminCredentials(context));
Iterator<Authorizable> result = session.getUserManager().findAuthorizables(new Query() {
@Override
public <T> void build(QueryBuilder<T> builder) {
builder.setSelector(Group.class);
}
});
while (result.hasNext()) {
Authorizable group = result.next();
log.info("group {} found",group.getPrincipal().getName());
groups.add(group.getPrincipal().getName());
}
session = (JackrabbitSession) repository.getRepository().login(Constants.JCR_CREDENTIALS);
groups = groupHandler.getGroups(session);
}catch(RepositoryException re ){
log.error("jcr error creating item", re);
GXOutboundErrorResponse.throwException(new BackendGenericError("jcr error creating item", re));
@ -142,32 +90,14 @@ public class GroupManager {
@POST
@Path("")
@Consumes(MediaType.MULTIPART_FORM_DATA)
@AuthorizationControl(allowedRoles={INFRASTRUCTURE_MANAGER_ROLE}, exception=MyAuthException.class)
public String createGroup(@FormDataParam("group") String group, @FormDataParam("accessType") AccessType accessType, @FormDataParam("folderOwner") String folderOwner){
InnerMethodName.instance.set("createGroup");
@AuthorizationControl(allowedRoles={INFRASTRUCTURE_MANAGER_ROLE})
public String createGroup(@FormDataParam("group") String group, @FormDataParam("accessType") AccessType accessType, @FormDataParam("folderOwner") String folderOwner, @FormDataParam("useDefaultStorage") @DefaultValue("true") boolean useDefaultStorage){
InnerMethodName.set("createGroup");
JackrabbitSession session = null;
String groupId = null;
try {
log.info("create group called with groupid {} , accessType {} and folderOwner {}",group, accessType, folderOwner);
session = (JackrabbitSession) repository.getRepository().login(CredentialHandler.getAdminCredentials(context));
org.apache.jackrabbit.api.security.user.UserManager usrManager = session.getUserManager();
Group createdGroup = usrManager.createGroup(group);
groupId = createdGroup.getID();
User user = (User)usrManager.getAuthorizable(folderOwner);
createVreFolder(groupId, session, accessType!=null?accessType:AccessType.WRITE_OWNER, folderOwner);
boolean success = this.internalAddUserToGroup(session, createdGroup, user);
if (!success) log.warn("the user have not been added to the group");
else log.debug("the user have been added to the group");
session = (JackrabbitSession) repository.getRepository().login(Constants.JCR_CREDENTIALS);
groupHandler.createGroup(session, group, accessType, folderOwner, useDefaultStorage);
session.save();
}catch(StorageHubException se) {
log.error("error creating group {}", group, se);
@ -179,37 +109,19 @@ public class GroupManager {
if (session!=null)
session.logout();
}
return groupId;
return group;
}
@DELETE
@Path("{group}")
@AuthorizationControl(allowedRoles={INFRASTRUCTURE_MANAGER_ROLE}, exception=MyAuthException.class)
@AuthorizationControl(allowedRoles={INFRASTRUCTURE_MANAGER_ROLE})
public String deleteGroup(@PathParam("group") String group){
InnerMethodName.instance.set("deleteGroup");
InnerMethodName.set("deleteGroup");
JackrabbitSession session = null;
try {
session = (JackrabbitSession) repository.getRepository().login(CredentialHandler.getAdminCredentials(context));
org.apache.jackrabbit.api.security.user.UserManager usrManager = session.getUserManager();
Authorizable authorizable = usrManager.getAuthorizable(group);
if (authorizable!=null && authorizable.isGroup())
authorizable.remove();
try {
Node node = groupHandler.getFolderNodeRelatedToGroup(session, group);
List<Item> workspaceItems = Utils.getItemList(node, Excludes.GET_ONLY_CONTENT, null, true, null);
trashHandler.removeOnlyNodesContent(session, workspaceItems);
node.removeSharedSet();
}catch (Exception e) {
log.warn("vreFolder {} not found, removing only the group", group);
}
session = (JackrabbitSession) repository.getRepository().login(Constants.JCR_CREDENTIALS);
groupHandler.deleteGroup(session, group);
session.save();
}catch(RepositoryException re ){
log.error("jcr error creating item", re);
@ -222,51 +134,32 @@ public class GroupManager {
}
public boolean isInfraManager() { return AuthorizationProvider.instance.get().getClient().getRoles().contains(INFRASTRUCTURE_MANAGER_ROLE); }
public boolean isInfraManager() { return SecretManagerProvider.get().getOwner().getRoles().contains(INFRASTRUCTURE_MANAGER_ROLE); }
public boolean isVREManager() { return AuthorizationProvider.instance.get().getClient().getRoles().contains(VREMANAGER_ROLE); }
public boolean isVREManager() { return SecretManagerProvider.get().getOwner().getRoles().contains(VREMANAGER_ROLE); }
@PUT
@Path("{id}/admins")
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
public void addAdmin(@PathParam("id") String groupId, @FormParam("userId") String userId){
InnerMethodName.instance.set("addAdmin");
InnerMethodName.set("addAdmin");
JackrabbitSession session = null;
try {
Objects.nonNull(groupId);
Objects.nonNull(userId);
Objects.nonNull(userId);
session = (JackrabbitSession) repository.getRepository().login(CredentialHandler.getAdminCredentials(context));
Node vreFolder = groupHandler.getFolderNodeRelatedToGroup(session, groupId);
String currentUser = AuthorizationProvider.instance.get().getClient().getId();
String currentUser = SecretManagerProvider.get().getOwner().getId();
if (!isInfraManager() && !(isVREManager() && isValidGroupForContext(groupId) ))
authChecker.checkAdministratorControl(session, currentUser, node2Item.getItem(vreFolder, Excludes.ALL));
org.apache.jackrabbit.api.security.user.UserManager usrManager = ((JackrabbitSession)session).getUserManager();
Group group = (Group)usrManager.getAuthorizable(groupId);
User authUser = (User)usrManager.getAuthorizable(userId);
if (group ==null)
throw new InvalidCallParameters("invalid group "+groupId);
if (authUser ==null)
throw new InvalidCallParameters("invalid user "+userId);
if (!isInfraManager() && !(isVREManager() && isValidGroupForContext(groupId)) &&
!groupHandler.getGroupAdministators(session, groupId).contains(currentUser))
throw new UserNotAuthorizedException();
if (!group.isMember(authUser))
throw new InvalidCallParameters("user "+userId+" is not in the group "+groupId);
session = (JackrabbitSession) repository.getRepository().login(Constants.JCR_CREDENTIALS);
groupHandler.addAdministratorToGroup(session, groupId, userId);
AccessControlManager acm = session.getAccessControlManager();
JackrabbitAccessControlList acls = AccessControlUtils.getAccessControlList(acm, vreFolder.getPath());
Privilege[] userPrivileges = new Privilege[] { acm.privilegeFromName(AccessType.ADMINISTRATOR.getValue()) };
Principal principal = AccessControlUtils.getPrincipal(session, userId);
acls.addAccessControlEntry(principal, userPrivileges);
acm.setPolicy(vreFolder.getPath(), acls);
session.save();
}catch(StorageHubException she ){
log.error(she.getErrorMessage(), she);
@ -278,6 +171,8 @@ public class GroupManager {
if (session!=null)
session.logout();
}
}
@DELETE
@ -285,35 +180,23 @@ public class GroupManager {
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
public void removeAdmin(@PathParam("id") String groupId, @PathParam("userId") String userId){
InnerMethodName.instance.set("removeAdmin");
JackrabbitSession session = null;
InnerMethodName.set("removeAdmin");
JackrabbitSession session = null;
try {
Objects.nonNull(groupId);
Objects.nonNull(userId);
session = (JackrabbitSession) repository.getRepository().login(CredentialHandler.getAdminCredentials(context));
Node vreFolder = groupHandler.getFolderNodeRelatedToGroup(session, groupId);
String currentUser = AuthorizationProvider.instance.get().getClient().getId();
String currentUser = SecretManagerProvider.get().getOwner().getId();
if (!isInfraManager() && !(isVREManager() && isValidGroupForContext(groupId) ))
authChecker.checkAdministratorControl(session, currentUser, node2Item.getItem(vreFolder, Excludes.ALL));
if (!isInfraManager() && !(isVREManager() && isValidGroupForContext(groupId)) &&
!groupHandler.getGroupAdministators(session, groupId).contains(currentUser))
throw new UserNotAuthorizedException();
session = (JackrabbitSession) repository.getRepository().login(Constants.JCR_CREDENTIALS);
groupHandler.removeAdministratorFromGroup(session, groupId, userId);
AccessControlManager acm = session.getAccessControlManager();
JackrabbitAccessControlList acls = AccessControlUtils.getAccessControlList(acm, vreFolder.getPath());
AccessControlEntry toRemove = null;
for (AccessControlEntry acl: acls.getAccessControlEntries())
if (acl.getPrincipal().getName().equals(userId)) {
toRemove = acl;
break;
}
acls.removeAccessControlEntry(toRemove);
acm.setPolicy(vreFolder.getPath(), acls);
session.save();
}catch(StorageHubException she ){
log.error(she.getErrorMessage(), she);
@ -321,7 +204,7 @@ public class GroupManager {
}catch(Throwable re ){
log.error("jcr error creating item", re);
GXOutboundErrorResponse.throwException(new BackendGenericError("jcr error removing admin to VREFolder", re));
}finally {
} finally {
if (session!=null)
session.logout();
}
@ -332,37 +215,19 @@ public class GroupManager {
@Produces(MediaType.APPLICATION_JSON)
public List<String> getAdmins(@PathParam("groupId") String groupId){
InnerMethodName.instance.set("getAdmins");
String login = AuthorizationProvider.instance.get().getClient().getId();
JackrabbitSession session = null;
InnerMethodName.set("getAdmins");
List<String> users = new ArrayList<>();
JackrabbitSession session = null;
try {
session = (JackrabbitSession) repository.getRepository().login(CredentialHandler.getAdminCredentials(context));
VRE vreFolder = vreManager.getVreFolderItemByGroupName(session, groupId, login, Excludes.ALL);
AccessControlManager acm = session.getAccessControlManager();
//authChecker.checkAdministratorControl(session, (VreFolder)vreFolder.getVreFolder());
Node node = session.getNodeByIdentifier(vreFolder.getVreFolder().getId());
JackrabbitAccessControlList acls = AccessControlUtils.getAccessControlList(acm, node.getPath());
for (AccessControlEntry acl: acls.getAccessControlEntries())
for (Privilege pr: acl.getPrivileges()) {
if (pr.getName().equals(AccessType.ADMINISTRATOR.getValue())){
users.add(acl.getPrincipal().getName());
}
}
session = (JackrabbitSession) repository.getRepository().login(Constants.JCR_CREDENTIALS);
users = groupHandler.getGroupAdministators(session, groupId);
}catch(StorageHubException she ){
log.error(she.getErrorMessage(), she);
GXOutboundErrorResponse.throwException(she, Response.Status.fromStatusCode(she.getStatus()));
}catch(Exception re ){
log.error("jcr error creating item", re);
GXOutboundErrorResponse.throwException(new BackendGenericError("jcr error creating item", re));
}finally {
}catch(Throwable re ){
log.error("jcr error getting admins", re);
GXOutboundErrorResponse.throwException(new BackendGenericError("jcr error getting admins", re));
} finally {
if (session!=null)
session.logout();
}
@ -374,41 +239,29 @@ public class GroupManager {
@PUT
@Path("{id}/users")
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
@AuthorizationControl(allowedRoles={VREMANAGER_ROLE, INFRASTRUCTURE_MANAGER_ROLE}, exception=MyAuthException.class)
@AuthorizationControl(allowedRoles={VREMANAGER_ROLE, INFRASTRUCTURE_MANAGER_ROLE})
public boolean addUserToGroup(@PathParam("id") String groupId, @FormParam("userId") String userId){
InnerMethodName.instance.set("addUserToGroup");
InnerMethodName.set("addUserToGroup");
JackrabbitSession session = null;
boolean success = false;
try {
if (!isInfraManager() && !isValidGroupForContext(groupId))
if (!isInfraManager() && !(isVREManager() && isValidGroupForContext(groupId)))
throw new UserNotAuthorizedException("only VREManager of the selected VRE can execute this operation");
session = (JackrabbitSession) repository.getRepository().login(CredentialHandler.getAdminCredentials(context));
org.apache.jackrabbit.api.security.user.UserManager usrManager = session.getUserManager();
Group group = (Group)usrManager.getAuthorizable(groupId);
User user = (User)usrManager.getAuthorizable(userId);
if (user==null)
throw new InvalidCallParameters("user "+userId+" not exists");
if (group.isMember(user))
throw new InvalidCallParameters("user "+userId+" is already member of group "+groupId);
this.internalAddUserToGroup(session, group, user);
session = (JackrabbitSession) repository.getRepository().login(Constants.JCR_CREDENTIALS);
groupHandler.addUserToGroup(session, userId, groupId);
success = true;
session.save();
}catch(StorageHubException she ){
log.error(she.getErrorMessage(), she);
GXOutboundErrorResponse.throwException(she, Response.Status.fromStatusCode(she.getStatus()));
}catch(RepositoryException re ){
log.error("jcr error creating item", re);
GXOutboundErrorResponse.throwException(new BackendGenericError("jcr error creating item", re));
}finally {
log.error("jcr error adding user to group", re);
GXOutboundErrorResponse.throwException(new BackendGenericError("jcr error adding user to group", re));
} finally {
if (session!=null)
session.logout();
}
@ -416,43 +269,25 @@ public class GroupManager {
return success;
}
private boolean internalAddUserToGroup(JackrabbitSession session, Group group, User user) throws RepositoryException, StorageHubException {
boolean success = group.addMember(user);
session.save();
String folderName = group.getPrincipal().getName();
Node folder = groupHandler.getFolderNodeRelatedToGroup(session, folderName);
String userPath = Paths.append(pathUtil.getVREsPath(user.getPrincipal().getName(), session), folderName).toPath();
log.debug("creating folder in user path {} from {}", userPath, folder.getPath() );
session.getWorkspace().clone(session.getWorkspace().getName(), folder.getPath(),userPath , false);
try {
session.getNode(userPath);
log.debug("the new folder exists ({}) ", userPath );
}catch (PathNotFoundException e) {
log.debug("the new folder doesn't exists ({}) ", userPath );
}
return success;
}
@DELETE
@Path("{groupId}/users/{userId}")
@AuthorizationControl(allowedRoles={VREMANAGER_ROLE, INFRASTRUCTURE_MANAGER_ROLE}, exception=MyAuthException.class)
@AuthorizationControl(allowedRoles={VREMANAGER_ROLE, INFRASTRUCTURE_MANAGER_ROLE})
public boolean removeUserFromGroup(@PathParam("groupId") String groupId, @PathParam("userId") String userId){
InnerMethodName.instance.set("removeUserFromGroup");
InnerMethodName.set("removeUserFromGroup");
JackrabbitSession session = null;
boolean success = false;
try {
if (!isValidGroupForContext(groupId) && !isInfraManager())
if (!isInfraManager() && !(isVREManager() && isValidGroupForContext(groupId)))
throw new UserNotAuthorizedException("only VREManager of the selected VRE can execute this operation");
session = (JackrabbitSession) repository.getRepository().login(CredentialHandler.getAdminCredentials(context));
session = (JackrabbitSession) repository.getRepository().login(Constants.JCR_CREDENTIALS);
success = groupHandler.removeUserFromGroup(groupId, userId, session);
success = groupHandler.removeUserFromGroup(session, groupId, userId);
session.save();
}catch(StorageHubException she ){
@ -472,39 +307,25 @@ public class GroupManager {
@GET
@Path("{groupId}/users")
@Produces(MediaType.APPLICATION_JSON)
@AuthorizationControl(allowedRoles={VREMANAGER_ROLE, INFRASTRUCTURE_MANAGER_ROLE}, exception=MyAuthException.class)
@AuthorizationControl(allowedRoles={VREMANAGER_ROLE, INFRASTRUCTURE_MANAGER_ROLE})
public List<String> getUsersOfGroup(@PathParam("groupId") String groupId){
InnerMethodName.instance.set("getUsersOfGroup");
InnerMethodName.set("getUsersOfGroup");
JackrabbitSession session = null;
List<String> users = new ArrayList<>();
try {
if (!isValidGroupForContext(groupId) && !isInfraManager())
if (!isInfraManager() && !(isVREManager() && isValidGroupForContext(groupId)))
throw new UserNotAuthorizedException("only VREManager of the selected VRE can execute this operation");
session = (JackrabbitSession) repository.getRepository().login(CredentialHandler.getAdminCredentials(context));
org.apache.jackrabbit.api.security.user.UserManager usrManager = session.getUserManager();
Group group = (Group)usrManager.getAuthorizable(groupId);
Iterator<Authorizable> it = group.getMembers();
while (it.hasNext()) {
Authorizable user = it.next();
users.add(user.getPrincipal().getName());
}
}catch(StorageHubException she ){
log.error(she.getErrorMessage(), she);
GXOutboundErrorResponse.throwException(she, Response.Status.fromStatusCode(she.getStatus()));
session = (JackrabbitSession) repository.getRepository().login(Constants.JCR_CREDENTIALS);
users = groupHandler.getUsersBelongingToGroup(session, groupId);
}catch (StorageHubException e) {
log.error("error getting users", e);
GXOutboundErrorResponse.throwException(e);
}catch(RepositoryException re ){
log.error("jcr error creating item", re);
GXOutboundErrorResponse.throwException(new BackendGenericError("jcr error creating item", re));
}finally {
log.error("jcr error getting users", re);
GXOutboundErrorResponse.throwException(new BackendGenericError("jcr error getting users", re));
} finally {
if (session!=null)
session.logout();
}
@ -512,51 +333,11 @@ public class GroupManager {
return users;
}
private void createVreFolder(String groupId, JackrabbitSession session, AccessType defaultAccessType, String owner ) throws Exception{
Node sharedRootNode = session.getNode(Constants.SHARED_FOLDER_PATH);
String name = groupId;
String currentScope = ScopeProvider.instance.get();
ScopeBean bean = new ScopeBean(currentScope);
while (!bean.is(Type.INFRASTRUCTURE)) {
bean = bean.enclosingScope();
}
String root = bean.toString().replaceAll("/", "");
String displayName = groupId.replaceAll(root+"-[^\\-]*\\-(.*)", "$1");
log.info("creating vreFolder with name {} and title {} and owner {}", name, displayName, owner);
FolderCreationParameters folderParameters = FolderCreationParameters.builder().name(name).description( "VREFolder for "+groupId).author(owner).on(sharedRootNode.getIdentifier()).with(session).build();
Node folder= Utils.createFolderInternally(folderParameters, null);
folder.setPrimaryType(PrimaryNodeType.NT_WORKSPACE_SHARED_FOLDER);
folder.setProperty(NodeProperty.IS_VRE_FOLDER.toString(), true);
folder.setProperty(NodeProperty.TITLE.toString(), name);
folder.setProperty(NodeProperty.DISPLAY_NAME.toString(), displayName);
session.save();
AccessControlManager acm = session.getAccessControlManager();
JackrabbitAccessControlList acls = AccessControlUtils.getAccessControlList(acm, folder.getPath());
/*Privilege[] adminPrivileges = new Privilege[] { acm.privilegeFromName(AccessType.ADMINISTRATOR.getValue()) };
acls.addAccessControlEntry(AccessControlUtils.getPrincipal(session, AuthorizationProvider.instance.get().getClient().getId()), adminPrivileges );
*/
Privilege[] usersPrivileges = new Privilege[] { acm.privilegeFromName(defaultAccessType.getValue()) };
acls.addAccessControlEntry(AccessControlUtils.getPrincipal(session,groupId), usersPrivileges );
acm.setPolicy(folder.getPath(), acls);
log.debug("vrefolder created with id {}",folder.getIdentifier());
}
private boolean isValidGroupForContext(String group){
String currentContext = ScopeProvider.instance.get();
String currentContext = SecretManagerProvider.get().getContext();
String expectedGroupId= currentContext.replace("/", "-").substring(1);
return group.equals(expectedGroupId);
}

View File

@ -3,18 +3,20 @@ package org.gcube.data.access.storagehub.services;
import static org.gcube.data.access.storagehub.Roles.INFRASTRUCTURE_MANAGER_ROLE;
import javax.enterprise.context.RequestScoped;
import javax.inject.Inject;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.Path;
import javax.ws.rs.core.Context;
import org.gcube.common.authorization.library.provider.AuthorizationProvider;
import org.gcube.common.authorization.library.provider.ClientInfo;
import org.gcube.common.security.Owner;
import org.gcube.common.security.providers.SecretManagerProvider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.enterprise.context.RequestScoped;
import jakarta.inject.Inject;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.core.Context;
@Path("")
@ApplicationScoped
public abstract class Impersonable {
Logger log = LoggerFactory.getLogger(Impersonable.class);
@ -24,15 +26,14 @@ public abstract class Impersonable {
@RequestScoped
@Inject
public void setCurrentUser(@Context final HttpServletRequest request) {
String impersonate = request!=null ? request.getParameter("impersonate") : null ;
ClientInfo info = AuthorizationProvider.instance.get().getClient();
if(impersonate!=null && info.getRoles().contains(INFRASTRUCTURE_MANAGER_ROLE)) {
Owner owner = SecretManagerProvider.get().getOwner();
if(impersonate!=null && owner.getRoles().contains(INFRASTRUCTURE_MANAGER_ROLE)) {
this.currentUser = impersonate;
} else
this.currentUser = info.getId();
this.currentUser = owner.getId();
log.info("called with login {} and impersonate {}",info.getId(), impersonate);
log.info("called with login {} and impersonate {}",owner.getId(), impersonate);
}
}

View File

@ -4,24 +4,12 @@ import java.util.HashMap;
import java.util.Map.Entry;
import java.util.Set;
import javax.enterprise.context.RequestScoped;
import javax.inject.Inject;
import javax.jcr.Node;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.jcr.lock.LockException;
import javax.jcr.security.AccessControlManager;
import javax.jcr.security.Privilege;
import javax.servlet.ServletContext;
import javax.ws.rs.Consumes;
import javax.ws.rs.FormParam;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import org.apache.jackrabbit.api.security.JackrabbitAccessControlList;
import org.apache.jackrabbit.commons.jackrabbit.authorization.AccessControlUtils;
@ -43,26 +31,44 @@ import org.gcube.common.storagehub.model.types.PrimaryNodeType;
import org.gcube.data.access.storagehub.AuthorizationChecker;
import org.gcube.data.access.storagehub.Constants;
import org.gcube.data.access.storagehub.PathUtil;
import org.gcube.data.access.storagehub.StorageHubAppllicationManager;
import org.gcube.data.access.storagehub.Utils;
import org.gcube.data.access.storagehub.accounting.AccountingHandler;
import org.gcube.data.access.storagehub.handlers.CredentialHandler;
import org.gcube.data.access.storagehub.handlers.UnshareHandler;
import org.gcube.data.access.storagehub.handlers.items.Item2NodeConverter;
import org.gcube.data.access.storagehub.handlers.items.Node2ItemConverter;
import org.gcube.data.access.storagehub.repository.StoragehubRepository;
import org.gcube.smartgears.utils.InnerMethodName;
import org.glassfish.jersey.media.multipart.FormDataParam;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.webcohesion.enunciate.metadata.rs.RequestHeader;
import com.webcohesion.enunciate.metadata.rs.RequestHeaders;
import jakarta.enterprise.context.RequestScoped;
import jakarta.inject.Inject;
import jakarta.servlet.ServletContext;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.FormParam;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.PUT;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.core.Context;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
@Path("items")
@RequestHeaders({
@RequestHeader( name = "Authorization", description = "Bearer token, see https://dev.d4science.org/how-to-access-resources"),
})
public class ItemSharing extends Impersonable{
private static final Logger log = LoggerFactory.getLogger(ItemSharing.class);
RepositoryInitializer repository = StorageHubAppllicationManager.repository;
private final StoragehubRepository repository = StoragehubRepository.repository;
@Inject
AccountingHandler accountingHandler;
@ -73,10 +79,10 @@ public class ItemSharing extends Impersonable{
@Context
ServletContext context;
@Inject
AuthorizationChecker authChecker;
@Inject
PathUtil pathUtil;
@ -86,15 +92,15 @@ public class ItemSharing extends Impersonable{
@Inject Node2ItemConverter node2Item;
@Inject Item2NodeConverter item2Node;
@SuppressWarnings("unchecked")
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
@POST
@Path("{id}/share")
public String shareWithMap(@FormParam("mapUserPermission") String mapUserPermissionString, @FormParam("defaultAccessType") String defaultAccessTypeString){
InnerMethodName.instance.set("shareFolder");
InnerMethodName.set("shareFolder");
HashMap<String,String> mapUserPermission;
Session ses = null;
String toReturn = null;
try{
@ -105,17 +111,17 @@ public class ItemSharing extends Impersonable{
}
AccessType defaultAccessType;
try {
defaultAccessType = AccessType.fromValue(defaultAccessTypeString);
defaultAccessType = AccessType.fromValue(defaultAccessTypeString);
}catch (IllegalArgumentException e) {
throw new InvalidCallParameters("invalid default accessType");
}
ses = repository.getRepository().login(CredentialHandler.getAdminCredentials(context));
ses = repository.getRepository().login(Constants.JCR_CREDENTIALS);
authChecker.checkWriteAuthorizationControl(ses, currentUser, id, false);
Item item = node2Item.getItem(ses.getNodeByIdentifier(id), Excludes.ALL);
if (mapUserPermission==null || mapUserPermission.isEmpty())
throw new InvalidCallParameters("users is empty");
@ -194,13 +200,12 @@ public class ItemSharing extends Impersonable{
@PUT
@Path("{id}/share")
@Consumes(MediaType.MULTIPART_FORM_DATA)
@Deprecated
public String share(@FormDataParam("users") Set<String> users, @FormDataParam("defaultAccessType") AccessType accessType){
InnerMethodName.instance.set("shareFolder");
InnerMethodName.set("shareFolder");
Session ses = null;
String toReturn = null;
try{
ses = repository.getRepository().login(CredentialHandler.getAdminCredentials(context));
ses = repository.getRepository().login(Constants.JCR_CREDENTIALS);
authChecker.checkWriteAuthorizationControl(ses, currentUser, id, false);
Item item = node2Item.getItem(ses.getNodeByIdentifier(id), Excludes.ALL);
@ -211,6 +216,8 @@ public class ItemSharing extends Impersonable{
if (users==null || users.isEmpty())
throw new InvalidCallParameters("users is empty");
log.info("shared method called with users {} and default access type {} ", users, accessType.getValue());
Node nodeToShare = ses.getNodeByIdentifier(id);
boolean alreadyShared = false;
@ -244,8 +251,9 @@ public class ItemSharing extends Impersonable{
for (String user : users)
try {
addUserToSharing(sharedFolderNode, ses, user, null, userPrivileges, acls);
log.info("added user {} to the shared node",user);
}catch(Exception e){
log.warn("error adding user {} to sharing of folder {}", user, sharedFolderNode.getName());
log.warn("error adding user {} to sharing of folder {}", user, sharedFolderNode.getName(),e);
}
acm.setPolicy(sharedFolderNode.getPath(), acls);
@ -267,6 +275,9 @@ public class ItemSharing extends Impersonable{
}catch(StorageHubException she ){
log.error(she.getErrorMessage(), she);
GXOutboundErrorResponse.throwException(she, Response.Status.fromStatusCode(she.getStatus()));
}catch(Exception e){
log.error("jcr sharing", e);
GXOutboundErrorResponse.throwException(new BackendGenericError("jcr error sharing folder", e));
}finally{
if (ses!=null)
ses.logout();
@ -278,7 +289,7 @@ public class ItemSharing extends Impersonable{
private Node shareFolder(Node node, Session ses) throws RepositoryException, BackendGenericError, StorageHubException{
if (!node2Item.checkNodeType(node, FolderItem.class) || Utils.hasSharedChildren(node) || !node.getProperty(NodeProperty.PORTAL_LOGIN.toString()).getString().equals(currentUser))
throw new InvalidItemException("item with id "+id+" cannot be shared");
@ -296,30 +307,35 @@ public class ItemSharing extends Impersonable{
}
private void addUserToSharing(Node sharedFolderNode, Session ses, String user, Item itemToShare, Privilege[] userPrivileges, JackrabbitAccessControlList acls) throws RepositoryException{
String userRootWSId;
String userPath;
if (itemToShare==null) {
String userRootWS = pathUtil.getWorkspacePath(user).toPath();
userRootWSId = ses.getNode(userRootWS).getIdentifier();
userPath = String.format("%s%s",userRootWS,sharedFolderNode.getProperty(NodeProperty.TITLE.toString()).getString());
try {
String userRootWSId;
String userPath;
if (itemToShare==null) {
String userRootWS = pathUtil.getWorkspacePath(user).toPath();
userRootWSId = ses.getNode(userRootWS).getIdentifier();
userPath = String.format("%s%s",userRootWS,sharedFolderNode.getProperty(NodeProperty.TITLE.toString()).getString());
}
else {
userPath = itemToShare.getPath();
userRootWSId = itemToShare.getParentId();
}
log.info("cloning directory to {} ",userPath);
ses.getWorkspace().clone(ses.getWorkspace().getName(), sharedFolderNode.getPath(), userPath , false);
acls.addAccessControlEntry(AccessControlUtils.getPrincipal(ses, user), userPrivileges );
Node usersNode =null;
if (sharedFolderNode.hasNode(NodeConstants.USERS_NAME))
usersNode = sharedFolderNode.getNode(NodeConstants.USERS_NAME);
else
usersNode = sharedFolderNode.addNode(NodeConstants.USERS_NAME);
usersNode.setProperty(user, String.format("%s/%s",userRootWSId,sharedFolderNode.getProperty(NodeProperty.TITLE.toString()).getString()));
}catch (Exception e) {
log.error("error sharing node with user {}",user,e);
throw new RepositoryException(e);
}
else {
userPath = itemToShare.getPath();
userRootWSId = itemToShare.getParentId();
}
log.info("cloning directory to {} ",userPath);
ses.getWorkspace().clone(ses.getWorkspace().getName(), sharedFolderNode.getPath(), userPath , false);
acls.addAccessControlEntry(AccessControlUtils.getPrincipal(ses, user), userPrivileges );
Node usersNode =null;
if (sharedFolderNode.hasNode(NodeConstants.USERS_NAME))
usersNode = sharedFolderNode.getNode(NodeConstants.USERS_NAME);
else
usersNode = sharedFolderNode.addNode(NodeConstants.USERS_NAME);
usersNode.setProperty(user, String.format("%s/%s",userRootWSId,sharedFolderNode.getProperty(NodeProperty.TITLE.toString()).getString()));
}
@ -327,12 +343,12 @@ public class ItemSharing extends Impersonable{
@Path("{id}/unshare")
@Consumes(MediaType.MULTIPART_FORM_DATA)
public String unshare(@FormDataParam("users") Set<String> users){
InnerMethodName.instance.set("unshareFolder");
InnerMethodName.set("unshareFolder");
Session ses = null;
String toReturn = null;
try {
log.debug("unsharing folder with id {} with users {}", id, users);
ses = repository.getRepository().login(CredentialHandler.getAdminCredentials(context));
ses = repository.getRepository().login(Constants.JCR_CREDENTIALS);
Node sharedNode = ses.getNodeByIdentifier(id);
toReturn = unshareHandler.unshare(ses, users, sharedNode, currentUser);
if(toReturn == null ) throw new InvalidItemException("item with id "+id+" cannot be unshared");

View File

@ -1,29 +1,22 @@
package org.gcube.data.access.storagehub.services;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.net.URL;
import java.net.URLConnection;
import javax.inject.Inject;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.servlet.ServletContext;
import javax.ws.rs.Consumes;
import javax.ws.rs.FormParam;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import org.apache.commons.compress.archivers.ArchiveException;
import org.gcube.common.gxrest.response.outbound.GXOutboundErrorResponse;
import org.gcube.common.storagehub.model.exceptions.BackendGenericError;
import org.gcube.common.storagehub.model.exceptions.StorageHubException;
import org.gcube.common.storagehub.model.items.GCubeItem;
import org.gcube.data.access.storagehub.StorageHubAppllicationManager;
import org.gcube.data.access.storagehub.handlers.CredentialHandler;
import org.gcube.data.access.storagehub.Constants;
import org.gcube.data.access.storagehub.StorageHubApplicationManager;
import org.gcube.data.access.storagehub.handlers.items.ItemHandler;
import org.gcube.data.access.storagehub.handlers.items.builders.ArchiveStructureCreationParameter;
import org.gcube.data.access.storagehub.handlers.items.builders.FileCreationParameters;
@ -31,6 +24,7 @@ import org.gcube.data.access.storagehub.handlers.items.builders.FolderCreationPa
import org.gcube.data.access.storagehub.handlers.items.builders.GCubeItemCreationParameters;
import org.gcube.data.access.storagehub.handlers.items.builders.ItemsParameterBuilder;
import org.gcube.data.access.storagehub.handlers.items.builders.URLCreationParameters;
import org.gcube.data.access.storagehub.repository.StoragehubRepository;
import org.gcube.smartgears.annotations.ManagedBy;
import org.gcube.smartgears.utils.InnerMethodName;
import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
@ -38,32 +32,49 @@ import org.glassfish.jersey.media.multipart.FormDataParam;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.webcohesion.enunciate.metadata.rs.RequestHeader;
import com.webcohesion.enunciate.metadata.rs.RequestHeaders;
import jakarta.inject.Inject;
import jakarta.servlet.ServletContext;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.FormParam;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.core.Context;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
@Path("items")
@ManagedBy(StorageHubAppllicationManager.class)
@ManagedBy(StorageHubApplicationManager.class)
@RequestHeaders({
@RequestHeader( name = "Authorization", description = "Bearer token, see https://dev.d4science.org/how-to-access-resources"),
})
public class ItemsCreator extends Impersonable{
private static final Logger log = LoggerFactory.getLogger(ItemsCreator.class);
@Context
ServletContext context;
RepositoryInitializer repository = StorageHubAppllicationManager.repository;
private final StoragehubRepository repository = StoragehubRepository.repository;
@Inject
ItemHandler itemHandler;
@POST
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
@Path("/{id}/create/FOLDER")
public Response createFolder(@PathParam("id") String id, @FormParam("name") String name,
@FormParam("description") String description, @FormParam("hidden") boolean hidden) {
InnerMethodName.instance.set("createItem(FOLDER)");
InnerMethodName.set("createItem(FOLDER)");
log.info("create folder item called");
Session ses = null;
String toReturn = null;
try{
ses = repository.getRepository().login(CredentialHandler.getAdminCredentials(context));
ses = repository.getRepository().login(Constants.JCR_CREDENTIALS);
ItemsParameterBuilder<FolderCreationParameters> builder = FolderCreationParameters.builder().name(name).description(description).hidden(hidden).on(id).with(ses).author(currentUser);
toReturn = itemHandler.create(builder.build());
}catch(StorageHubException she ){
@ -90,13 +101,13 @@ public class ItemsCreator extends Impersonable{
@FormParam("description") String description, @FormParam("hidden") boolean hidden,
@FormParam("pluginName") String pluginName,
@FormParam("parameters") String pluginParameters) {
InnerMethodName.instance.set("createItem(EXTERNALFOLDER)");
InnerMethodName.set("createItem(EXTERNALFOLDER)");
log.info("create folder item called");
Session ses = null;
String toReturn = null;
try{
//TODO
ses = repository.getRepository().login(CredentialHandler.getAdminCredentials(context));
ses = repository.getRepository().login(Constants.JCR_CREDENTIALS);
ItemsParameterBuilder<FolderCreationParameters> builder = FolderCreationParameters.builder().name(name)
.description(description).onRepository(pluginName).withParameters(null).hidden(hidden).on(id).with(ses).author(currentUser);
toReturn = itemHandler.create(builder.build());
@ -116,18 +127,18 @@ public class ItemsCreator extends Impersonable{
}
return Response.ok(toReturn).build();
}
@POST
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
@Path("/{id}/create/URL")
public Response createURL(@PathParam("id") String id, @FormParam("name") String name, @FormParam("description") String description, @FormParam("value") URL value) {
InnerMethodName.instance.set("createItem(URL)");
InnerMethodName.set("createItem(URL)");
log.info("create url called");
Session ses = null;
String toReturn = null;
try{
ses = repository.getRepository().login(CredentialHandler.getAdminCredentials(context));
ses = repository.getRepository().login(Constants.JCR_CREDENTIALS);
ItemsParameterBuilder<URLCreationParameters> builder = URLCreationParameters.builder().name(name).description(description).url(value).on(id).with(ses).author(currentUser);
toReturn = itemHandler.create(builder.build());
@ -147,21 +158,21 @@ public class ItemsCreator extends Impersonable{
}
return Response.ok(toReturn).build();
}
@POST
@Consumes(MediaType.APPLICATION_JSON)
@Path("/{id}/create/GCUBEITEM")
public String createGcubeItem(@PathParam("id") String id, GCubeItem item) {
InnerMethodName.instance.set("createItem(GCUBEITEM)");
InnerMethodName.set("createItem(GCUBEITEM)");
log.info("create Gcube item called");
Session ses = null;
String toReturn = null;
try{
ses = repository.getRepository().login(CredentialHandler.getAdminCredentials(context));
ses = repository.getRepository().login(Constants.JCR_CREDENTIALS);
ItemsParameterBuilder<GCubeItemCreationParameters> builder = GCubeItemCreationParameters.builder().item(item).on(id).with(ses).author(currentUser);
toReturn = itemHandler.create(builder.build());
}catch(StorageHubException she ){
log.error(she.getErrorMessage(), she);
@ -181,24 +192,32 @@ public class ItemsCreator extends Impersonable{
@POST
@Consumes(MediaType.MULTIPART_FORM_DATA)
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
@Path("/{id}/create/FILE")
public String createFileItem(@PathParam("id") String id, @FormDataParam("name") String name,
@FormDataParam("description") String description,
@FormDataParam("file") InputStream stream,
@FormDataParam("file") FormDataContentDisposition fileDetail){
InnerMethodName.instance.set("createItem(FILE)");
public String createFileItemFromUrl(@PathParam("id") String id, @FormParam("name") String name,
@FormParam("description") String description,
@FormParam("url") String url){
InnerMethodName.set("createItem(FILEFromUrl)");
Session ses = null;
String toReturn = null;
try{
log.debug("UPLOAD: call started");
ses = repository.getRepository().login(Constants.JCR_CREDENTIALS);
ses = repository.getRepository().login(CredentialHandler.getAdminCredentials(context));
ItemsParameterBuilder<FileCreationParameters> builder = FileCreationParameters.builder().name(name).description(description).stream(stream).fileDetails(fileDetail)
.on(id).with(ses).author(currentUser);
toReturn = itemHandler.create(builder.build());
URLConnection connectionURL = new URI(url).toURL().openConnection();
long fileLength = connectionURL.getContentLengthLong();
try(InputStream stream = connectionURL.getInputStream()){
ItemsParameterBuilder<FileCreationParameters> builder = FileCreationParameters.builder().name(name).fileDetails(FormDataContentDisposition.name(name).size(fileLength).build())
.description(description).stream(stream)
.on(id).with(ses).author(currentUser);
toReturn = itemHandler.create(builder.build());
}
log.debug("UPLOAD: call finished");
}catch(RepositoryException re ){
log.error("jcr error creating file item", re);
GXOutboundErrorResponse.throwException(new BackendGenericError("jcr error creating file item", re));
@ -218,10 +237,83 @@ public class ItemsCreator extends Impersonable{
}
@POST
@Consumes(MediaType.MULTIPART_FORM_DATA)
@Path("/{id}/create/FILE")
public String createFileItem(@PathParam("id") String id, @FormDataParam("name") String name,
@FormDataParam("description") String description,
@FormDataParam("file") InputStream stream,
@FormDataParam("file") FormDataContentDisposition fileDetail){
InnerMethodName.set("createItem(FILE)");
Session ses = null;
String toReturn = null;
try(InputStream is = new BufferedInputStream(stream)){
long size = fileDetail.getSize();
log.info("UPLOAD: call started with file size {}",size);
ses = repository.getRepository().login(Constants.JCR_CREDENTIALS);
ItemsParameterBuilder<FileCreationParameters> builder = FileCreationParameters.builder().name(name).description(description).stream(stream).fileDetails(fileDetail)
.on(id).with(ses).author(currentUser);
log.debug("UPLOAD: item prepared");
toReturn = itemHandler.create(builder.build());
log.debug("UPLOAD: call finished");
}catch(RepositoryException re ){
log.error("jcr error creating file item", re);
GXOutboundErrorResponse.throwException(new BackendGenericError("jcr error creating file item", re));
}catch(StorageHubException she ){
log.error(she.getErrorMessage(), she);
GXOutboundErrorResponse.throwException(she, Response.Status.fromStatusCode(she.getStatus()));
}catch(Throwable e ){
log.error("unexpected error", e);
GXOutboundErrorResponse.throwException(new BackendGenericError(e));
}finally{
if (ses!=null && ses.isLive()) {
log.info("session closed");
ses.logout();
}
}
return toReturn;
}
@POST
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
@Path("/{id}/create/ARCHIVE")
public String uploadArchiveFromURL(@PathParam("id") String id, @FormParam("parentFolderName") String parentFolderName,
@FormParam("url") String url){
InnerMethodName.set("createItem(ARCHIVEFromURL)");
Session ses = null;
String toReturn = null;
try{
ses = repository.getRepository().login(Constants.JCR_CREDENTIALS);
try(InputStream stream = new URI(url).toURL().openStream()){
ItemsParameterBuilder<ArchiveStructureCreationParameter> builder = ArchiveStructureCreationParameter.builder().parentName(parentFolderName).stream(stream)
.on(id).with(ses).author(currentUser);
toReturn = itemHandler.create(builder.build());
}
}catch(RepositoryException | ArchiveException | IOException re){
log.error("jcr error extracting archive", re);
GXOutboundErrorResponse.throwException(new BackendGenericError("jcr error extracting archive", re));
}catch(StorageHubException she ){
log.error(she.getErrorMessage(), she);
GXOutboundErrorResponse.throwException(she, Response.Status.fromStatusCode(she.getStatus()));
}catch(Throwable e ){
log.error("unexpected error", e);
GXOutboundErrorResponse.throwException(new BackendGenericError(e));
} finally{
if (ses!=null)
ses.logout();
}
return toReturn;
}
@POST
@Consumes(MediaType.MULTIPART_FORM_DATA)
@ -229,16 +321,16 @@ public class ItemsCreator extends Impersonable{
public String uploadArchive(@PathParam("id") String id, @FormDataParam("parentFolderName") String parentFolderName,
@FormDataParam("file") InputStream stream,
@FormDataParam("file") FormDataContentDisposition fileDetail){
InnerMethodName.instance.set("createItem(ARCHIVE)");
InnerMethodName.set("createItem(ARCHIVE)");
Session ses = null;
String toReturn = null;
try{
ses = repository.getRepository().login(CredentialHandler.getAdminCredentials(context));
try(InputStream is = new BufferedInputStream(stream)){
ses = repository.getRepository().login(Constants.JCR_CREDENTIALS);
ItemsParameterBuilder<ArchiveStructureCreationParameter> builder = ArchiveStructureCreationParameter.builder().parentName(parentFolderName).stream(stream).fileDetails(fileDetail)
ItemsParameterBuilder<ArchiveStructureCreationParameter> builder = ArchiveStructureCreationParameter.builder().parentName(parentFolderName).stream(is).fileDetails(fileDetail)
.on(id).with(ses).author(currentUser);
toReturn = itemHandler.create(builder.build());
}catch(RepositoryException | ArchiveException | IOException re){
@ -259,6 +351,6 @@ public class ItemsCreator extends Impersonable{
}
}

View File

@ -1,24 +1,13 @@
package org.gcube.data.access.storagehub.services;
import static org.gcube.common.storagehub.model.Constants.enchriptedPrefix;
import static org.gcube.common.storagehub.model.Constants.versionPrefix;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Base64;
import java.util.Collections;
import java.util.Deque;
import java.util.LinkedList;
import java.util.List;
import java.util.zip.Deflater;
import java.util.zip.ZipOutputStream;
import javax.enterprise.context.RequestScoped;
import javax.inject.Inject;
import javax.jcr.ItemNotFoundException;
import javax.jcr.Node;
import javax.jcr.NodeIterator;
@ -26,39 +15,16 @@ import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.jcr.lock.LockException;
import javax.jcr.version.Version;
import javax.servlet.ServletContext;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.FormParam;
import javax.ws.rs.GET;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import javax.ws.rs.core.StreamingOutput;
import org.apache.commons.io.FilenameUtils;
import org.gcube.common.authorization.control.annotations.AuthorizationControl;
import org.gcube.common.encryption.encrypter.StringEncrypter;
import org.gcube.common.gxrest.response.outbound.GXOutboundErrorResponse;
import org.gcube.common.scope.api.ScopeProvider;
import org.gcube.common.scope.impl.ScopeBean;
import org.gcube.common.scope.impl.ScopeBean.Type;
import org.gcube.common.storagehub.model.Excludes;
import org.gcube.common.storagehub.model.NodeConstants;
import org.gcube.common.storagehub.model.Paths;
import org.gcube.common.storagehub.model.exceptions.BackendGenericError;
import org.gcube.common.storagehub.model.exceptions.IdNotFoundException;
import org.gcube.common.storagehub.model.exceptions.InvalidCallParameters;
import org.gcube.common.storagehub.model.exceptions.InvalidItemException;
import org.gcube.common.storagehub.model.exceptions.ItemLockedException;
import org.gcube.common.storagehub.model.exceptions.PluginInitializationException;
import org.gcube.common.storagehub.model.exceptions.PluginNotFoundException;
import org.gcube.common.storagehub.model.exceptions.StorageHubException;
import org.gcube.common.storagehub.model.items.AbstractFileItem;
import org.gcube.common.storagehub.model.items.FolderItem;
@ -66,43 +32,66 @@ import org.gcube.common.storagehub.model.items.Item;
import org.gcube.common.storagehub.model.items.SharedFolder;
import org.gcube.common.storagehub.model.items.VreFolder;
import org.gcube.common.storagehub.model.items.nodes.Content;
import org.gcube.common.storagehub.model.plugins.FolderManager;
import org.gcube.common.storagehub.model.service.ItemList;
import org.gcube.common.storagehub.model.service.ItemWrapper;
import org.gcube.common.storagehub.model.service.VersionList;
import org.gcube.common.storagehub.model.storages.MetaInfo;
import org.gcube.common.storagehub.model.types.ItemAction;
import org.gcube.common.storagehub.model.types.NodeProperty;
import org.gcube.data.access.storagehub.AuthorizationChecker;
import org.gcube.data.access.storagehub.Constants;
import org.gcube.data.access.storagehub.PathUtil;
import org.gcube.data.access.storagehub.Range;
import org.gcube.data.access.storagehub.SingleFileStreamingOutput;
import org.gcube.data.access.storagehub.StorageHubAppllicationManager;
import org.gcube.data.access.storagehub.StorageHubApplicationManager;
import org.gcube.data.access.storagehub.Utils;
import org.gcube.data.access.storagehub.accounting.AccountingHandler;
import org.gcube.data.access.storagehub.exception.MyAuthException;
import org.gcube.data.access.storagehub.handlers.ClassHandler;
import org.gcube.data.access.storagehub.handlers.CompressHandler;
import org.gcube.data.access.storagehub.handlers.CredentialHandler;
import org.gcube.data.access.storagehub.handlers.DownloadHandler;
import org.gcube.data.access.storagehub.handlers.PublicLinkHandler;
import org.gcube.data.access.storagehub.handlers.TrashHandler;
import org.gcube.data.access.storagehub.handlers.VersionHandler;
import org.gcube.data.access.storagehub.handlers.items.Item2NodeConverter;
import org.gcube.data.access.storagehub.handlers.items.Node2ItemConverter;
import org.gcube.data.access.storagehub.handlers.plugins.FolderPluginHandler;
import org.gcube.data.access.storagehub.handlers.plugins.StorageOperationMediator;
import org.gcube.data.access.storagehub.repository.StoragehubRepository;
import org.gcube.data.access.storagehub.types.PublicLink;
import org.gcube.smartgears.annotations.ManagedBy;
import org.gcube.smartgears.utils.InnerMethodName;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.webcohesion.enunciate.metadata.rs.RequestHeader;
import com.webcohesion.enunciate.metadata.rs.RequestHeaders;
import jakarta.enterprise.context.RequestScoped;
import jakarta.inject.Inject;
import jakarta.servlet.ServletContext;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.DELETE;
import jakarta.ws.rs.FormParam;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.PUT;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.QueryParam;
import jakarta.ws.rs.core.Context;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.core.Response.Status;
@Path("items")
@ManagedBy(StorageHubAppllicationManager.class)
@ManagedBy(StorageHubApplicationManager.class)
@RequestHeaders({
@RequestHeader( name = "Authorization", description = "Bearer token, see https://dev.d4science.org/how-to-access-resources"),
})
public class ItemsManager extends Impersonable{
private static final Logger log = LoggerFactory.getLogger(ItemsManager.class);
RepositoryInitializer repository = StorageHubAppllicationManager.repository;
private final StoragehubRepository repository = StoragehubRepository.repository;
@Inject
AccountingHandler accountingHandler;
@ -115,35 +104,40 @@ public class ItemsManager extends Impersonable{
@Inject
AuthorizationChecker authChecker;
@Inject
VersionHandler versionHandler;
@Inject
DownloadHandler downloadHandler;
@Inject
TrashHandler trashHandler;
@Inject PathUtil pathUtil;
@Inject Node2ItemConverter node2Item;
@Inject Item2NodeConverter item2Node;
@Inject
FolderPluginHandler folderPluginHandler;
StorageOperationMediator opMediator;
@Inject
CompressHandler compressHandler;
PublicLinkHandler publicLinkHandler;
@GET
@Path("{id}")
@Produces(MediaType.APPLICATION_JSON)
public ItemWrapper<Item> getById(@QueryParam("exclude") List<String> excludes){
InnerMethodName.instance.set("getById");
InnerMethodName.set("getById");
Session ses = null;
Item toReturn = null;
try{
ses = repository.getRepository().login(CredentialHandler.getAdminCredentials(context));
ses = repository.getRepository().login(Constants.JCR_CREDENTIALS);
Node node = ses.getNodeByIdentifier(id);
authChecker.checkReadAuthorizationControl(ses, currentUser, id);
toReturn = node2Item.getItem(node, excludes);
@ -168,11 +162,11 @@ public class ItemsManager extends Impersonable{
@Path("{id}/path")
@Produces(MediaType.APPLICATION_JSON)
public ItemWrapper<Item> getByRelativePath(@QueryParam("path") String path, @QueryParam("exclude") List<String> excludes){
InnerMethodName.instance.set("getByPath");
InnerMethodName.set("getByPath");
Session ses = null;
Item toReturn = null;
try{
ses = repository.getRepository().login(CredentialHandler.getAdminCredentials(context));
ses = repository.getRepository().login(Constants.JCR_CREDENTIALS);
authChecker.checkReadAuthorizationControl(ses, currentUser, id);
String relativePath = path.startsWith("/")? path.substring(1) : path;
@ -230,7 +224,7 @@ public class ItemsManager extends Impersonable{
@Path("{id}/items/{name}")
@Produces(MediaType.APPLICATION_JSON)
public ItemList findChildrenByNamePatternInPath(@QueryParam("exclude") List<String> excludes, @PathParam("name") String name){
InnerMethodName.instance.set("findChildrenByNamePattern");
InnerMethodName.set("findChildrenByNamePattern");
return _findChildrenByNamePattern(excludes, name);
}
@ -238,15 +232,15 @@ public class ItemsManager extends Impersonable{
@Path("{id}/items")
@Produces(MediaType.APPLICATION_JSON)
public ItemList findChildrenByNamePattern(@QueryParam("exclude") List<String> excludes, @QueryParam("name") String name){
InnerMethodName.instance.set("findChildrenByNamePattern");
InnerMethodName.set("findChildrenByNamePattern");
return _findChildrenByNamePattern(excludes, name);
}
public ItemList _findChildrenByNamePattern(List<String> excludes, String name){
Session ses = null;
List<Item> toReturn = new ArrayList<>();
try{
ses = repository.getRepository().login(CredentialHandler.getAdminCredentials(context));
ses = repository.getRepository().login(Constants.JCR_CREDENTIALS);
authChecker.checkReadAuthorizationControl(ses, currentUser, id);
//NOT using the internal pattern matching of jcr because of title for shared folder
@ -278,21 +272,21 @@ public class ItemsManager extends Impersonable{
if (ses!=null)
ses.logout();
}
return new ItemList(toReturn);
}
@GET
@Path("{id}/children/count")
@Produces(MediaType.APPLICATION_JSON)
public Long countById(@QueryParam("showHidden") Boolean showHidden, @QueryParam("exclude") List<String> excludes, @QueryParam("onlyType") String nodeType){
InnerMethodName.instance.set("countById");
InnerMethodName.set("countById");
Session ses = null;
Long toReturn = null;
try{
ses = repository.getRepository().login(CredentialHandler.getAdminCredentials(context));
ses = repository.getRepository().login(Constants.JCR_CREDENTIALS);
authChecker.checkReadAuthorizationControl(ses, currentUser, id);
toReturn = Utils.getItemCount(ses.getNodeByIdentifier(id), showHidden==null?false:showHidden, nodeType!=null ? ClassHandler.instance().get(nodeType) : null);
}catch (ItemNotFoundException e) {
@ -315,11 +309,11 @@ public class ItemsManager extends Impersonable{
@Path("{id}/children")
@Produces(MediaType.APPLICATION_JSON)
public ItemList listById(@QueryParam("showHidden") Boolean showHidden, @QueryParam("exclude") List<String> excludes, @QueryParam("onlyType") String nodeType){
InnerMethodName.instance.set("listById");
InnerMethodName.set("listById");
Session ses = null;
List<? extends Item> toReturn = null;
try{
ses = repository.getRepository().login(CredentialHandler.getAdminCredentials(context));
ses = repository.getRepository().login(Constants.JCR_CREDENTIALS);
authChecker.checkReadAuthorizationControl(ses, currentUser, id);
toReturn = Utils.getItemList(ses.getNodeByIdentifier(id), excludes, null, showHidden==null?false:showHidden, nodeType!=null ? ClassHandler.instance().get(nodeType) : null);
}catch (ItemNotFoundException e) {
@ -343,12 +337,12 @@ public class ItemsManager extends Impersonable{
@Path("{id}/search")
@Produces(MediaType.APPLICATION_JSON)
public ItemList searchItems(@QueryParam("showHidden") Boolean showHidden, @QueryParam("excludeTrashed") Boolean excludeTrashed, @QueryParam("exclude") List<String> excludes, @QueryParam("onlyType") String nodeType,@QueryParam("name") String name ){
InnerMethodName.instance.set("search");
InnerMethodName.set("search");
Session ses = null;
List<? extends Item> toReturn = null;
try{
log.debug("search for node {}",name);
ses = repository.getRepository().login(CredentialHandler.getAdminCredentials(context));
ses = repository.getRepository().login(Constants.JCR_CREDENTIALS);
authChecker.checkReadAuthorizationControl(ses, currentUser, id);
toReturn = Utils.searchByNameOnFolder(ses, currentUser, authChecker, ses.getNodeByIdentifier(id), excludes, null, showHidden==null?false:showHidden,excludeTrashed==true?false:excludeTrashed , nodeType!=null ? ClassHandler.instance().get(nodeType) : null, name);
log.debug("search retrieved {} elements",toReturn.size());
@ -373,11 +367,11 @@ public class ItemsManager extends Impersonable{
@Path("{id}/children/paged")
@Produces(MediaType.APPLICATION_JSON)
public ItemList listByIdPaged(@QueryParam("showHidden") Boolean showHidden, @QueryParam("start") Integer start, @QueryParam("limit") Integer limit, @QueryParam("exclude") List<String> excludes, @QueryParam("onlyType") String nodeType){
InnerMethodName.instance.set("listByIdPaged");
InnerMethodName.set("listByIdPaged");
Session ses = null;
List<? extends Item> toReturn = null;
try{
ses = repository.getRepository().login(CredentialHandler.getAdminCredentials(context));
ses = repository.getRepository().login(Constants.JCR_CREDENTIALS);
authChecker.checkReadAuthorizationControl(ses, currentUser, id);
toReturn = Utils.getItemList(ses.getNodeByIdentifier(id), excludes, new Range(start, limit),showHidden==null?false:showHidden, nodeType!=null ? ClassHandler.instance().get(nodeType) : null);
}catch (ItemNotFoundException e) {
@ -399,62 +393,26 @@ public class ItemsManager extends Impersonable{
@GET
@Path("publiclink/{id}")
@AuthorizationControl(allowedUsers={"URIResolver"}, exception=MyAuthException.class)
@AuthorizationControl(allowedUsers={"URIResolver"})
public Response resolvePublicLink() {
InnerMethodName.instance.set("resolvePubliclink");
InnerMethodName.set("resolvePubliclink");
log.warn("arrived id is {}",id);
Session ses = null;
try{
ses = repository.getRepository().login(CredentialHandler.getAdminCredentials(context));
String complexId = id;
if (id.startsWith(enchriptedPrefix)) {
String currentScope = ScopeProvider.instance.get();
try {
ScopeBean bean= new ScopeBean(currentScope);
while (!bean.is(Type.INFRASTRUCTURE)) {
bean = bean.enclosingScope();
}
ScopeProvider.instance.set(bean.toString());
complexId = StringEncrypter.getEncrypter().decrypt(new String(Base64.getUrlDecoder().decode(id.replace(enchriptedPrefix, ""))));
}catch(Exception e){
throw new BackendGenericError("invalid public url",e);
}finally {
ScopeProvider.instance.set(currentScope);
}
ses = repository.getRepository().login(Constants.JCR_CREDENTIALS);
PublicLink publicLink = publicLinkHandler.resolveEnchriptedId(id);
switch (publicLink.getType()) {
case VOLATILE:
return downloadHandler.downloadFileFromStorageBackend(publicLink.getId(), publicLink.getStorageName());
case VERSIONED:
Item versionedItem = node2Item.getItem(publicLink.getId(), ses, Excludes.GET_ONLY_CONTENT);
return downloadHandler.downloadVersionedItem(ses, currentUser, (AbstractFileItem) versionedItem, publicLink.getVersion(), true);
default:
Item currentItem = node2Item.getItem(publicLink.getId(), ses, Excludes.GET_ONLY_CONTENT);
return downloadHandler.downloadFileItem(ses,(AbstractFileItem) currentItem, currentUser, true);
}
String itemId = complexId;
String versionName = null;
if (complexId.contains(versionPrefix)) {
String[] split = complexId.split(versionPrefix);
itemId = split[0];
versionName = split[1];
}
log.warn("item id to retrieve is {}",itemId);
Node selectedNode;
try {
selectedNode= ses.getNodeByIdentifier(itemId);
}catch (ItemNotFoundException e) {
throw new IdNotFoundException(itemId);
}
Item item = node2Item.getItem(selectedNode, Arrays.asList(NodeConstants.ACCOUNTING_NAME, NodeConstants.METADATA_NAME));
if (!(item instanceof AbstractFileItem)) throw new InvalidCallParameters("the choosen item is not a File");
if (versionName!=null)
return downloadVersionInternal(ses, currentUser, itemId, versionName, false);
else
return downloadFileInternal(ses, (AbstractFileItem) item, currentUser, true);
}catch(RepositoryException re ){
log.error("jcr error getting public link", re);
GXOutboundErrorResponse.throwException(new BackendGenericError(re));
@ -472,11 +430,11 @@ public class ItemsManager extends Impersonable{
@Produces(MediaType.APPLICATION_JSON)
@Path("{id}/publiclink")
public URL getPublicLink(@QueryParam("version") String version) {
InnerMethodName.instance.set("getPubliclink");
InnerMethodName.set("getPubliclink");
Session ses = null;
URL toReturn = null;
try{
ses = repository.getRepository().login(CredentialHandler.getAdminCredentials(context));
ses = repository.getRepository().login(Constants.JCR_CREDENTIALS);
authChecker.checkReadAuthorizationControl(ses, currentUser, id);
Node selectedNode = ses.getNodeByIdentifier(id);
@ -505,28 +463,10 @@ public class ItemsManager extends Impersonable{
ses.getWorkspace().getLockManager().unlock(selectedNode.getPath());
}*/
String url = null;
String currentScope = ScopeProvider.instance.get();
try {
ScopeBean bean= new ScopeBean(currentScope);
while (!bean.is(Type.INFRASTRUCTURE)) {
bean = bean.enclosingScope();
}
ScopeProvider.instance.set(bean.toString());
String url = version!=null ? publicLinkHandler.getForVersionedItem(id, version, context):
publicLinkHandler.getForItem(id, context);
String toEnchript;
if(version!=null) toEnchript = String.format("%s%s%s",id, versionPrefix, version);
else toEnchript = id;
String enchriptedQueryString = StringEncrypter.getEncrypter().encrypt(toEnchript);
url = createPublicLink(new String(Base64.getUrlEncoder().encode(enchriptedQueryString.getBytes())));
}catch(Exception e){
throw new BackendGenericError(e);
}finally {
ScopeProvider.instance.set(currentScope);
}
toReturn = new URL(url);
@ -545,21 +485,19 @@ public class ItemsManager extends Impersonable{
}
private String createPublicLink(String enchriptedString) {
String basepath = context.getInitParameter("resolver-basepath");
String filePublicUrl = String.format("%s/%s%s",basepath, enchriptedPrefix, enchriptedString);
return filePublicUrl;
}
@PUT
@Path("{id}/publish")
@Produces(MediaType.APPLICATION_JSON)
public String makeFolderPublic(@FormParam("publish") boolean publish){
InnerMethodName.instance.set("makeFolderPublic("+publish+")");
InnerMethodName.set("makeFolderPublic("+publish+")");
Session ses = null;
Item folder= null;
try{
ses = repository.getRepository().login(CredentialHandler.getAdminCredentials(context));
ses = repository.getRepository().login(Constants.JCR_CREDENTIALS);
authChecker.checkWriteAuthorizationControl(ses, currentUser, id, false);
Node currentNode =ses.getNodeByIdentifier(id);
log.trace("current node is {}",currentNode.getPath());
@ -574,7 +512,7 @@ public class ItemsManager extends Impersonable{
ses.save();
}catch(RepositoryException re ){
log.error("jcr error getting rootSharedFolder", re);
log.error("jcr error publishing folder", re);
GXOutboundErrorResponse.throwException(new BackendGenericError(re));
}catch(StorageHubException she ){
log.error(she.getErrorMessage(), she);
@ -591,11 +529,11 @@ public class ItemsManager extends Impersonable{
@Path("{id}/rootSharedFolder")
@Produces(MediaType.APPLICATION_JSON)
public ItemWrapper<Item> getRootSharedFolder(@QueryParam("exclude") List<String> excludes){
InnerMethodName.instance.set("getRootSharedFolder");
InnerMethodName.set("getRootSharedFolder");
Session ses = null;
Item sharedParent= null;
try{
ses = repository.getRepository().login(CredentialHandler.getAdminCredentials(context));
ses = repository.getRepository().login(Constants.JCR_CREDENTIALS);
authChecker.checkReadAuthorizationControl(ses, currentUser, id);
Node currentNode =ses.getNodeByIdentifier(id);
log.trace("current node is {}",currentNode.getPath());
@ -634,11 +572,11 @@ public class ItemsManager extends Impersonable{
@Path("{id}/versions")
@Produces(MediaType.APPLICATION_JSON)
public VersionList getVersions(){
InnerMethodName.instance.set("getVersions");
InnerMethodName.set("getVersions");
Session ses = null;
List<org.gcube.common.storagehub.model.service.Version> versions = new ArrayList<>();
try{
ses = repository.getRepository().login(CredentialHandler.getAdminCredentials(context));
ses = repository.getRepository().login(Constants.JCR_CREDENTIALS);
authChecker.checkReadAuthorizationControl(ses, currentUser, id);
Node node = ses.getNodeByIdentifier(id);
@ -670,13 +608,17 @@ public class ItemsManager extends Impersonable{
@GET
@Path("{id}/versions/{version}/download")
public Response downloadVersion(@PathParam("version") String versionName){
InnerMethodName.instance.set("downloadSpecificVersion");
InnerMethodName.set("downloadSpecificVersion");
Session ses = null;
try{
ses = repository.getRepository().login(CredentialHandler.getAdminCredentials(context));
ses = repository.getRepository().login(Constants.JCR_CREDENTIALS);
authChecker.checkReadAuthorizationControl(ses, currentUser, id);
Node node = ses.getNodeByIdentifier(id);
Item currentItem = node2Item.getItem(node, Excludes.ALL);
if (!(currentItem instanceof AbstractFileItem))
throw new InvalidItemException("this item is not a file");
return downloadVersionInternal(ses, currentUser, id, versionName, true);
return downloadHandler.downloadVersionedItem(ses, currentUser, (AbstractFileItem) currentItem, versionName, true);
}catch(RepositoryException re ){
log.error("jcr error downloading version", re);
@ -691,56 +633,60 @@ public class ItemsManager extends Impersonable{
return Response.serverError().build();
}
private Response downloadVersionInternal(Session ses, String login, String id, String versionName, boolean withAccounting) throws RepositoryException, StorageHubException{
Node node = ses.getNodeByIdentifier(id);
Item currentItem = node2Item.getItem(node, Excludes.ALL);
if (!(currentItem instanceof AbstractFileItem))
throw new InvalidItemException("this item is not a file");
List<Version> jcrVersions = versionHandler.getContentVersionHistory(node);
for (Version version: jcrVersions) {
log.debug("retrieved version id {}, name {}", version.getIdentifier(), version.getName());
if (version.getName().equals(versionName)) {
Content content = node2Item.getContentFromVersion(version);
FolderManager folderManager = folderPluginHandler.getFolderManager((AbstractFileItem) currentItem);
final InputStream streamToWrite = folderManager.getStorageBackend().download(content);
log.debug("retrieved storage id is {} with storageBackend {} (stream is null? {})",content.getStorageId(), folderManager.getStorageBackend().getClass().getSimpleName(), streamToWrite==null );
String oldfilename = FilenameUtils.getBaseName(currentItem.getTitle());
String ext = FilenameUtils.getExtension(currentItem.getTitle());
String fileName = String.format("%s_v%s.%s", oldfilename, version.getName(), ext);
if (withAccounting)
accountingHandler.createReadObj(fileName, ses, node, login, true);
StreamingOutput so = new SingleFileStreamingOutput(streamToWrite);
return Response
.ok(so)
.header("content-disposition","attachment; filename = "+fileName)
.header("Content-Length", content.getSize())
.header("Content-Type", content.getMimeType())
.build();
}
@DELETE
@Path("{id}/versions/{version}")
public void deleteVersion(@PathParam("version") String versionName){
InnerMethodName.set("deleteVersion");
Session ses = null;
try{
ses = repository.getRepository().login(Constants.JCR_CREDENTIALS);
authChecker.checkWriteAuthorizationControl(ses, currentUser, id, false);
Node node = ses.getNodeByIdentifier(id);
Item currentItem = node2Item.getItem(node, Excludes.GET_ONLY_CONTENT);
if (!(currentItem instanceof AbstractFileItem))
throw new InvalidItemException("this item is not a file");
List<Version> versions = versionHandler.getContentVersionHistory(node);
boolean found = false;
for(Version version : versions)
if (version.getName().equals(versionName)) {
boolean currentVersion = ((AbstractFileItem)currentItem).getContent().getStorageId().equals(version.getFrozenNode().getProperty(NodeProperty.STORAGE_ID.toString()).getString());
if (currentVersion)
throw new InvalidCallParameters("current version cannot be removed");
versionHandler.removeContentVersion(node, versionName);
accountingHandler.createVersionDeleted(currentItem.getTitle(), versionName, ses, node, currentUser, false);
ses.save();
found = true;
break;
}
if (!found) throw new InvalidItemException("the version "+versionName+" is not valid or is current version for item "+currentItem.getTitle());
}catch(RepositoryException re ){
log.error("jcr error removing version", re);
GXOutboundErrorResponse.throwException(new BackendGenericError(re));
}catch(StorageHubException she ){
log.error(she.getErrorMessage(), she);
GXOutboundErrorResponse.throwException(she, Response.Status.fromStatusCode(she.getStatus()));
}finally{
if (ses!=null)
ses.logout();
}
throw new InvalidItemException("the version is not valid");
}
@GET
@Path("{id}/anchestors")
@Produces(MediaType.APPLICATION_JSON)
public ItemList getAnchestors(@QueryParam("exclude") List<String> excludes){
InnerMethodName.instance.set("getAnchestors");
InnerMethodName.set("getAnchestors");
org.gcube.common.storagehub.model.Path absolutePath = pathUtil.getWorkspacePath(currentUser);
Session ses = null;
List<Item> toReturn = new LinkedList<>();
try{
ses = repository.getRepository().login(CredentialHandler.getAdminCredentials(context));
ses = repository.getRepository().login(Constants.JCR_CREDENTIALS);
authChecker.checkReadAuthorizationControl(ses, currentUser, id);
Node currentNode = ses.getNodeByIdentifier(id);
Item currentItem = node2Item.getItem(currentNode, excludes);
@ -790,50 +736,17 @@ public class ItemsManager extends Impersonable{
@GET
@Path("{id}/download")
public Response download(@QueryParam("exclude") List<String> excludes){
InnerMethodName.instance.set("downloadById");
InnerMethodName.set("downloadById");
Session ses = null;
Response response = null;
try{
ses = repository.getRepository().login(CredentialHandler.getAdminCredentials(context));
ses = repository.getRepository().login(Constants.JCR_CREDENTIALS);
final Node node = ses.getNodeByIdentifier(id);
authChecker.checkReadAuthorizationControl(ses, currentUser, id);
final Item item = node2Item.getItem(node, null);
if (item instanceof AbstractFileItem){
return downloadFileInternal(ses, (AbstractFileItem) item, currentUser, true);
return downloadHandler.downloadFileItem(ses, (AbstractFileItem) item, currentUser, true);
} else if (item instanceof FolderItem){
try {
final Deque<Item> allNodes = compressHandler.getAllNodesForZip((FolderItem)item, ses, currentUser, accountingHandler, excludes);
final org.gcube.common.storagehub.model.Path originalPath = Paths.getPath(item.getParentPath());
StreamingOutput so = new StreamingOutput() {
@Override
public void write(OutputStream os) {
try(ZipOutputStream zos = new ZipOutputStream(os)){
long start = System.currentTimeMillis();
zos.setLevel(Deflater.BEST_COMPRESSION);
log.debug("writing StreamOutput");
compressHandler.zipNode(zos, allNodes, currentUser, originalPath);
log.debug("StreamOutput written in {}",(System.currentTimeMillis()-start));
} catch (Exception e) {
log.error("error writing stream",e);
}
}
};
response = Response
.ok(so)
.header("content-disposition","attachment; filename = "+item.getTitle()+".zip")
.header("Content-Type", "application/zip")
.header("Content-Length", -1l)
.build();
accountingHandler.createReadObj(item.getTitle(), ses, (Node) item.getRelatedNode(), currentUser, false);
}finally {
if (ses!=null) ses.save();
}
return downloadHandler.downloadFolderItem(ses, currentUser, (FolderItem)item, true);
} else throw new InvalidItemException("item type not supported for download: "+item.getClass());
}catch(RepositoryException re ){
@ -845,40 +758,19 @@ public class ItemsManager extends Impersonable{
} finally{
if (ses!=null) ses.logout();
}
return response;
}
private Response downloadFileInternal(Session ses, AbstractFileItem fileItem, String login, boolean withAccounting) throws RepositoryException, PluginInitializationException, PluginNotFoundException, BackendGenericError {
FolderManager folderManager = folderPluginHandler.getFolderManager(fileItem);
final InputStream streamToWrite = folderManager.getStorageBackend().download(fileItem.getContent());
if (withAccounting)
accountingHandler.createReadObj(fileItem.getTitle(), ses, (Node) fileItem.getRelatedNode(), login, true);
StreamingOutput so = new SingleFileStreamingOutput(streamToWrite);
return Response
.ok(so)
.header("content-disposition","attachment; filename = "+fileItem.getName())
.header("Content-Length", fileItem.getContent().getSize())
.header("Content-Type", fileItem.getContent().getMimeType())
.build();
return null;
}
@PUT
@Path("{id}/move")
public String move(@FormParam("destinationId") String destinationId){
InnerMethodName.instance.set("move");
InnerMethodName.set("move");
Session ses = null;
try{
ses = repository.getRepository().login(CredentialHandler.getAdminCredentials(context));
ses = repository.getRepository().login(Constants.JCR_CREDENTIALS);
authChecker.checkMoveOpsForProtectedFolders(ses, id);
authChecker.checkWriteAuthorizationControl(ses, currentUser, destinationId, true);
@ -922,11 +814,12 @@ public class ItemsManager extends Impersonable{
if (movingSharedItemOutside)
item2Node.updateOwnerOnSubTree(nodeToMove, currentUser);
//folderHandler.onMove(source, destination);
//add onMove (if it changes the remotePath) and in case of different backend
accountingHandler.createFolderAddObj(uniqueName, item.getClass().getSimpleName(), mimeTypeForAccounting, ses, currentUser, destination, false);
accountingHandler.createFolderRemoveObj(item.getTitle(), item.getClass().getSimpleName(), mimeTypeForAccounting, ses, currentUser, originalParent, false);
ses.save();
}finally {
ses.getWorkspace().getLockManager().unlock(nodeToMove.getPath());
@ -950,20 +843,20 @@ public class ItemsManager extends Impersonable{
@PUT
@Path("{id}/copy")
public String copy(@FormParam("destinationId") String destinationId, @FormParam("fileName") String newFileName){
InnerMethodName.instance.set("copy");
InnerMethodName.set("copy");
//TODO: check if identifier is The Workspace root, or the trash folder or the VREFolder root or if the item is thrashed
Session ses = null;
String newFileIdentifier = null;
try{
ses = repository.getRepository().login(CredentialHandler.getAdminCredentials(context));
ses = repository.getRepository().login(Constants.JCR_CREDENTIALS);
authChecker.checkWriteAuthorizationControl(ses, currentUser, destinationId, true);
authChecker.checkReadAuthorizationControl(ses, currentUser, id);
final Node nodeToCopy = ses.getNodeByIdentifier(id);
final Node destination = ses.getNodeByIdentifier(destinationId);
//Item destinationItem = node2Item.getItem(destination,null);
FolderItem destinationItem = (FolderItem)node2Item.getItem(destination,null);
final Item item = node2Item.getItem(nodeToCopy, Arrays.asList(NodeConstants.ACCOUNTING_NAME, NodeConstants.METADATA_NAME));
@ -976,6 +869,7 @@ public class ItemsManager extends Impersonable{
}catch (LockException e) {
throw new ItemLockedException(e);
}
try {
String uniqueName = Utils.checkExistanceAndGetUniqueName(ses, destination, newFileName);
String newPath= String.format("%s/%s", destination.getPath(), uniqueName);
@ -983,15 +877,12 @@ public class ItemsManager extends Impersonable{
Node newNode = ses.getNode(newPath);
newFileIdentifier = newNode.getIdentifier();
//TODO: folderHandler.onCopy(source, destination);
if (item instanceof AbstractFileItem) {
FolderManager manager = folderPluginHandler.getFolderManager(item);
((AbstractFileItem) item).getContent().setRemotePath(newPath);
String newStorageID = manager.getStorageBackend().onCopy((AbstractFileItem) item);
((AbstractFileItem) item).getContent().setStorageId(newStorageID);
item2Node.replaceContent(newNode, (AbstractFileItem) item, ItemAction.CLONED);
}
Content contentToCopy = ((AbstractFileItem) item).getContent();
MetaInfo contentInfo = opMediator.copy(contentToCopy, destinationItem.getBackend(), destination.getPath(), uniqueName, currentUser);
Utils.setContentFromMetaInfo((AbstractFileItem) item, contentInfo);
item2Node.replaceContent(newNode, (AbstractFileItem) item, ItemAction.CLONED);
Utils.setPropertyOnChangeNode(newNode, currentUser, ItemAction.CLONED);
newNode.setProperty(NodeProperty.PORTAL_LOGIN.toString(), currentUser);
@ -1026,26 +917,25 @@ public class ItemsManager extends Impersonable{
@PUT
@Path("{id}/rename")
public Response rename(@FormParam("newName") String newName){
InnerMethodName.instance.set("rename");
InnerMethodName.set("rename");
Session ses = null;
try{
ses = repository.getRepository().login(CredentialHandler.getAdminCredentials(context));
ses = repository.getRepository().login(Constants.JCR_CREDENTIALS);
authChecker.checkMoveOpsForProtectedFolders(ses, id);
authChecker.checkWriteAuthorizationControl(ses, currentUser, id, false);
final Node nodeToMove = ses.getNodeByIdentifier(id);
final Item item = node2Item.getItem(nodeToMove, null);
if (item instanceof SharedFolder)
throw new InvalidItemException("shared folder");
if (Constants.FOLDERS_TO_EXLUDE.contains(item.getTitle()))
throw new InvalidItemException("protected folder cannot be renamed");
if (item instanceof SharedFolder)
if (getSharedParentNode(nodeToMove).getIdentifier() == item.getId())
throw new InvalidItemException("root shared folder name cannot be modfied");
String uniqueName = Utils.checkExistanceAndGetUniqueName(ses, nodeToMove.getParent(), newName);
try {
ses.getWorkspace().getLockManager().lock(nodeToMove.getPath(), true, true, 0,currentUser);
@ -1053,10 +943,7 @@ public class ItemsManager extends Impersonable{
}catch (LockException e) {
throw new ItemLockedException(e);
}
try {
String uniqueName = Utils.checkExistanceAndGetUniqueName(ses, nodeToMove.getParent(), newName);
String newPath = String.format("%s/%s", nodeToMove.getParent().getPath(), uniqueName);
nodeToMove.setProperty(NodeProperty.TITLE.toString(), uniqueName);
Utils.setPropertyOnChangeNode(nodeToMove, currentUser, ItemAction.RENAMED);
@ -1088,13 +975,13 @@ public class ItemsManager extends Impersonable{
@Consumes(MediaType.APPLICATION_JSON)
@Path("/{id}/hidden")
public Response setItemAsHidden(Boolean hidden){
InnerMethodName.instance.set("setHidden");
InnerMethodName.set("setHidden");
Session ses = null;
try{
ses = repository.getRepository().login(CredentialHandler.getAdminCredentials(context));
ses = repository.getRepository().login(Constants.JCR_CREDENTIALS);
authChecker.checkWriteAuthorizationControl(ses, currentUser, id, false);
@ -1133,13 +1020,13 @@ public class ItemsManager extends Impersonable{
@Consumes(MediaType.APPLICATION_JSON)
@Path("/{id}/description")
public Response setDescription(String description){
InnerMethodName.instance.set("setDescription");
InnerMethodName.set("setDescription");
Session ses = null;
try{
ses = repository.getRepository().login(CredentialHandler.getAdminCredentials(context));
ses = repository.getRepository().login(Constants.JCR_CREDENTIALS);
authChecker.checkWriteAuthorizationControl(ses, currentUser, id, false);
@ -1177,13 +1064,13 @@ public class ItemsManager extends Impersonable{
@Consumes(MediaType.APPLICATION_JSON)
@Path("/{id}/metadata")
public Response setMetadata(org.gcube.common.storagehub.model.Metadata metadata){
InnerMethodName.instance.set("updateMetadata");
InnerMethodName.set("updateMetadata");
Session ses = null;
try{
ses = repository.getRepository().login(CredentialHandler.getAdminCredentials(context));
ses = repository.getRepository().login(Constants.JCR_CREDENTIALS);
authChecker.checkWriteAuthorizationControl(ses, currentUser, id, false);
@ -1222,15 +1109,15 @@ public class ItemsManager extends Impersonable{
@DELETE
@Path("{id}")
public Response deleteItem(@QueryParam("force") boolean force){
InnerMethodName.instance.set("deleteItem("+force+")");
InnerMethodName.set("deleteItem("+force+")");
Session ses = null;
try{
log.info("removing node with id {}", id);
//TODO check if it is possible to change all the ACL on a workspace
ses = repository.getRepository().login(CredentialHandler.getAdminCredentials(context));
ses = repository.getRepository().login(Constants.JCR_CREDENTIALS);
authChecker.checkWriteAuthorizationControl(ses, currentUser, id, false);
authChecker.checkMoveOpsForProtectedFolders(ses, id);
@ -1243,7 +1130,7 @@ public class ItemsManager extends Impersonable{
if (itemToDelete.isExternalManaged() && !force)
throw new InvalidItemException("External managed Items cannot be moved to Trash");
log.debug("item is trashed? {}", itemToDelete.isTrashed());
if (!itemToDelete.isTrashed() && !force) {

View File

@ -5,28 +5,11 @@ import java.util.Arrays;
import java.util.List;
import java.util.UUID;
import javax.enterprise.context.RequestScoped;
import javax.inject.Inject;
import javax.jcr.ItemNotFoundException;
import javax.jcr.Node;
import javax.jcr.NodeIterator;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.servlet.ServletContext;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.FormParam;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import org.apache.jackrabbit.api.JackrabbitSession;
import org.apache.jackrabbit.api.security.user.User;
@ -40,37 +23,63 @@ import org.gcube.common.storagehub.model.exceptions.StorageHubException;
import org.gcube.common.storagehub.model.exceptions.UserNotAuthorizedException;
import org.gcube.common.storagehub.model.items.AbstractFileItem;
import org.gcube.common.storagehub.model.items.Item;
import org.gcube.common.storagehub.model.items.nodes.Content;
import org.gcube.common.storagehub.model.items.nodes.Owner;
import org.gcube.common.storagehub.model.messages.Message;
import org.gcube.common.storagehub.model.service.ItemList;
import org.gcube.common.storagehub.model.storages.MetaInfo;
import org.gcube.common.storagehub.model.storages.StorageBackend;
import org.gcube.common.storagehub.model.storages.StorageBackendFactory;
import org.gcube.common.storagehub.model.types.ItemAction;
import org.gcube.common.storagehub.model.types.MessageList;
import org.gcube.common.storagehub.model.types.NodeProperty;
import org.gcube.data.access.storagehub.Constants;
import org.gcube.data.access.storagehub.PathUtil;
import org.gcube.data.access.storagehub.StorageHubAppllicationManager;
import org.gcube.data.access.storagehub.StorageHubApplicationManager;
import org.gcube.data.access.storagehub.Utils;
import org.gcube.data.access.storagehub.accounting.AccountingHandler;
import org.gcube.data.access.storagehub.handlers.CredentialHandler;
import org.gcube.data.access.storagehub.handlers.TrashHandler;
import org.gcube.data.access.storagehub.handlers.items.Item2NodeConverter;
import org.gcube.data.access.storagehub.handlers.items.Item2NodeConverter.Values;
import org.gcube.data.access.storagehub.handlers.items.Node2ItemConverter;
import org.gcube.data.access.storagehub.handlers.plugins.FolderPluginHandler;
import org.gcube.data.access.storagehub.handlers.plugins.StorageBackendHandler;
import org.gcube.data.access.storagehub.repository.StoragehubRepository;
import org.gcube.data.access.storagehub.types.MessageSharable;
import org.gcube.smartgears.annotations.ManagedBy;
import org.gcube.smartgears.utils.InnerMethodName;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.webcohesion.enunciate.metadata.rs.RequestHeader;
import com.webcohesion.enunciate.metadata.rs.RequestHeaders;
import jakarta.enterprise.context.RequestScoped;
import jakarta.inject.Inject;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.DELETE;
import jakarta.ws.rs.FormParam;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.PUT;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.QueryParam;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.core.Response.Status;
@Path("messages")
@ManagedBy(StorageHubAppllicationManager.class)
@ManagedBy(StorageHubApplicationManager.class)
@RequestHeaders({
@RequestHeader( name = "Authorization", description = "Bearer token, see https://dev.d4science.org/how-to-access-resources"),
})
public class MessageManager extends Impersonable{
private static final Logger log = LoggerFactory.getLogger(MessageManager.class);
RepositoryInitializer repository = StorageHubAppllicationManager.repository;
private final StoragehubRepository repository = StoragehubRepository.repository;
@Inject
AccountingHandler accountingHandler;
@ -78,25 +87,25 @@ public class MessageManager extends Impersonable{
@PathParam("id")
String id;
@Context
ServletContext context;
@Inject PathUtil pathUtil;
@Inject Node2ItemConverter node2Item;
@Inject Item2NodeConverter item2Node;
@Inject TrashHandler trashHandler;
@Inject
StorageBackendHandler storageBackendHandler;
@GET
@Path("{id}")
@Produces(MediaType.APPLICATION_JSON)
public Message getById(){
InnerMethodName.instance.set("getMessageById");
InnerMethodName.set("getMessageById");
Session ses = null;
Message toReturn = null;
try{
ses = repository.getRepository().login(CredentialHandler.getAdminCredentials(context));
ses = repository.getRepository().login(Constants.JCR_CREDENTIALS);
Node messageNode = ses.getNodeByIdentifier(id);
toReturn = node2Item.getMessageItem(messageNode);
checkRights(currentUser, toReturn);
@ -120,17 +129,18 @@ public class MessageManager extends Impersonable{
@DELETE
@Path("{id}")
public void deleteById(){
InnerMethodName.instance.set("deleteMessageById");
InnerMethodName.set("deleteMessageById");
Session ses = null;
try{
ses = repository.getRepository().login(CredentialHandler.getAdminCredentials(context));
ses = repository.getRepository().login(Constants.JCR_CREDENTIALS);
Node messageNode = ses.getNodeByIdentifier(id);
Message message = node2Item.getMessageItem(messageNode);
Node personalNode = checkRights(currentUser, message);
if (countSharedSet(messageNode)>1)
personalNode.removeShare();
else {
if (countSharedSet(messageNode)>1) {
log.debug("removing node message "+personalNode.getPath());
personalNode.remove();
}else {
if (message.isWithAttachments()) {
Node attachmentNode = messageNode.getNode(Constants.ATTACHMENTNODE_NAME);
List<Item> attachments = Utils.getItemList(attachmentNode, Excludes.GET_ONLY_CONTENT, null, true, AbstractFileItem.class);
@ -139,6 +149,7 @@ public class MessageManager extends Impersonable{
messageNode.removeSharedSet();
}
ses.save();
log.debug("removing node message saved");
}catch (ItemNotFoundException e) {
log.error("id {} not found",id,e);
GXOutboundErrorResponse.throwException(new IdNotFoundException(id, e), Status.NOT_FOUND);
@ -158,11 +169,11 @@ public class MessageManager extends Impersonable{
@Path("{id}/attachments")
@Produces(MediaType.APPLICATION_JSON)
public ItemList getAttachments(){
InnerMethodName.instance.set("getAttachmentsByMessageId");
InnerMethodName.set("getAttachmentsByMessageId");
Session ses = null;
List<Item> attachments = new ArrayList<>();
try{
ses = repository.getRepository().login(CredentialHandler.getAdminCredentials(context));
ses = repository.getRepository().login(Constants.JCR_CREDENTIALS);
Node messageNode = ses.getNodeByIdentifier(id);
Message messageItem = node2Item.getMessageItem(messageNode);
checkRights(currentUser, messageItem);
@ -189,11 +200,11 @@ public class MessageManager extends Impersonable{
@Path("inbox")
@Produces(MediaType.APPLICATION_JSON)
public MessageList getReceivedMessages(@QueryParam("reduceBody") Integer reduceBody){
InnerMethodName.instance.set("getReceivedMessages");
InnerMethodName.set("getReceivedMessages");
Session ses = null;
List<Message> toReturn = null;
try{
ses = repository.getRepository().login(CredentialHandler.getAdminCredentials(context));
ses = repository.getRepository().login(Constants.JCR_CREDENTIALS);
Node node = ses.getNode(pathUtil.getInboxPath(currentUser).toPath());
@ -214,11 +225,11 @@ public class MessageManager extends Impersonable{
@Path("sent")
@Produces(MediaType.APPLICATION_JSON)
public MessageList getSentMessages(@QueryParam("reduceBody") Integer reduceBody){
InnerMethodName.instance.set("getSentMessages");
InnerMethodName.set("getSentMessages");
Session ses = null;
List<Message> toReturn = null;
try{
ses = repository.getRepository().login(CredentialHandler.getAdminCredentials(context));
ses = repository.getRepository().login(Constants.JCR_CREDENTIALS);
Node node = ses.getNode(pathUtil.getOutboxPath(currentUser).toPath());
@ -238,10 +249,10 @@ public class MessageManager extends Impersonable{
@Path("{id}/{prop}")
@Consumes(MediaType.APPLICATION_JSON)
public void setProperty(@PathParam("prop") String property,Object value){
InnerMethodName.instance.set("setPropertyOnMessage("+property+")");
InnerMethodName.set("setPropertyOnMessage("+property+")");
Session ses = null;
try{
ses = repository.getRepository().login(CredentialHandler.getAdminCredentials(context));
ses = repository.getRepository().login(Constants.JCR_CREDENTIALS);
Node messageNode = ses.getNodeByIdentifier(id);
Message messageItem = node2Item.getMessageItem(messageNode);
checkRights(currentUser, messageItem);
@ -271,7 +282,7 @@ public class MessageManager extends Impersonable{
public String sendMessage(@FormParam("to[]") List<String> addresses,
@FormParam("subject") String subject, @FormParam("body") String body,
@FormParam("attachments[]") List<String> attachments){
InnerMethodName.instance.set("sendMessage");
InnerMethodName.set("sendMessage");
JackrabbitSession ses = null;
String messageId = null;
try{
@ -280,7 +291,7 @@ public class MessageManager extends Impersonable{
log.debug("attachments send are {}",attachments);
ses = (JackrabbitSession) repository.getRepository().login(CredentialHandler.getAdminCredentials(context));
ses = (JackrabbitSession) repository.getRepository().login(Constants.JCR_CREDENTIALS);
Message message = new MessageSharable();
message.setAddresses(addresses.toArray(new String[0]));
@ -288,6 +299,9 @@ public class MessageManager extends Impersonable{
message.setBody(body);
message.setName(UUID.randomUUID().toString());
User user = ses.getUserManager().getAuthorizable(currentUser, User.class);
if (user ==null)
throw new InvalidCallParameters("invalid storagehub user: "+currentUser);
Owner owner = new Owner();
owner.setUserId(user.getID());
owner.setUserName(user.getPrincipal().getName());
@ -325,7 +339,7 @@ public class MessageManager extends Impersonable{
private Node saveAttachments(Session ses, Node messageNode , List<String> attachments) throws RepositoryException, BackendGenericError{
private Node saveAttachments(Session ses, Node messageNode , List<String> attachments) throws RepositoryException, StorageHubException{
Node attachmentNode = messageNode.getNode(Constants.ATTACHMENTNODE_NAME);
for (String itemId: attachments) {
@ -345,7 +359,7 @@ public class MessageManager extends Impersonable{
NodeIterator nodeIt = node.getNodes();
while(nodeIt.hasNext()) {
Node child = nodeIt.nextNode();
log.info("message type "+child.getPrimaryNodeType().getName());
log.trace("message type "+child.getPrimaryNodeType().getName());
Message message = node2Item.getMessageItem(child);
if (message == null) {
log.info("message discarded");
@ -375,13 +389,13 @@ public class MessageManager extends Impersonable{
private Node checkRights(String user, Message messageItem) throws RepositoryException, StorageHubException{
Node personalNode = null;
Node messageNode = (Node) messageItem.getRelatedNode();
if (messageNode.getPath().startsWith(pathUtil.getWorkspacePath(currentUser).toPath()))
if (messageNode.getPath().startsWith(pathUtil.getInboxPath(user).toPath()))
return messageNode;
NodeIterator nodeIt = messageNode.getSharedSet();
while (nodeIt.hasNext()) {
Node node = nodeIt.nextNode();
if (node.getPath().startsWith(pathUtil.getWorkspacePath(currentUser).toPath()))
if (node.getPath().startsWith(pathUtil.getInboxPath(user).toPath()))
personalNode = node;
}
if (personalNode == null &&
@ -390,10 +404,8 @@ public class MessageManager extends Impersonable{
return personalNode== null ? messageNode : personalNode;
}
//TODO: move in a common place
@Inject FolderPluginHandler folderPluginHandler;
private Node copyNode(Session session, Node destination, Item itemToCopy) throws RepositoryException, BackendGenericError{
private Node copyNode(Session session, Node destination, Item itemToCopy) throws RepositoryException, StorageHubException{
//it needs to be locked ??
Node nodeToCopy = ((Node)itemToCopy.getRelatedNode());
String uniqueName = Utils.checkExistanceAndGetUniqueName(session, destination,itemToCopy.getName() );
@ -403,9 +415,15 @@ public class MessageManager extends Impersonable{
if (itemToCopy instanceof AbstractFileItem) {
AbstractFileItem newNodeItem = node2Item.getItem(newNode, Excludes.EXCLUDE_ACCOUNTING);
newNodeItem.getContent().setRemotePath(newPath);
String newStorageID = folderPluginHandler.getDefault().getStorageBackend().onCopy(newNodeItem);
newNodeItem.getContent().setStorageId(newStorageID);
Content contentToCopy = newNodeItem.getContent();
StorageBackendFactory sbf = storageBackendHandler.get(contentToCopy.getPayloadBackend());
StorageBackend sb = sbf.create(contentToCopy.getPayloadBackend());
MetaInfo contentInfo = sb.onCopy(contentToCopy, destination.getPath(), uniqueName);
Utils.setContentFromMetaInfo(newNodeItem, contentInfo);
item2Node.replaceContent(newNode, newNodeItem, ItemAction.CLONED);
}

View File

@ -1,10 +0,0 @@
package org.gcube.data.access.storagehub.services;
import javax.jcr.Repository;
public interface RepositoryInitializer {
Repository getRepository();
void shutdown();
}

View File

@ -0,0 +1,40 @@
package org.gcube.data.access.storagehub.services;
import java.util.ArrayList;
import java.util.List;
import org.gcube.common.storagehub.model.storages.StorageDescriptor;
import org.gcube.data.access.storagehub.StorageHubApplicationManager;
import org.gcube.data.access.storagehub.handlers.plugins.StorageBackendHandler;
import org.gcube.smartgears.annotations.ManagedBy;
import org.gcube.smartgears.utils.InnerMethodName;
import com.webcohesion.enunciate.metadata.rs.RequestHeader;
import com.webcohesion.enunciate.metadata.rs.RequestHeaders;
import jakarta.inject.Inject;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;
@Path("storages")
@ManagedBy(StorageHubApplicationManager.class)
@RequestHeaders({
@RequestHeader( name = "Authorization", description = "Bearer token, see https://dev.d4science.org/how-to-access-resources"),
})
public class StorageManager {
@Inject
StorageBackendHandler storageBackendHandler;
@GET
@Path("/")
@Produces(MediaType.APPLICATION_JSON)
public List<StorageDescriptor> getStorages(){
InnerMethodName.set("getStorages");
List<StorageDescriptor> storages = new ArrayList<>();
storageBackendHandler.getAllImplementations().forEach( f -> storages.add(new StorageDescriptor(f.getName())));
return storages;
}
}

View File

@ -1,157 +1,94 @@
package org.gcube.data.access.storagehub.services;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import javax.inject.Inject;
import javax.jcr.Node;
import javax.jcr.PathNotFoundException;
import javax.jcr.RepositoryException;
import javax.servlet.ServletContext;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.FormParam;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import org.apache.jackrabbit.api.JackrabbitSession;
import org.apache.jackrabbit.api.security.user.Authorizable;
import org.apache.jackrabbit.api.security.user.Group;
import org.apache.jackrabbit.api.security.user.Query;
import org.apache.jackrabbit.api.security.user.QueryBuilder;
import org.apache.jackrabbit.api.security.user.User;
import org.apache.jackrabbit.core.security.principal.PrincipalImpl;
import org.gcube.common.authorization.control.annotations.AuthorizationControl;
import org.gcube.common.gxrest.response.outbound.GXOutboundErrorResponse;
import org.gcube.common.storagehub.model.Excludes;
import org.gcube.common.storagehub.model.exceptions.BackendGenericError;
import org.gcube.common.storagehub.model.exceptions.IdNotFoundException;
import org.gcube.common.storagehub.model.exceptions.StorageHubException;
import org.gcube.common.storagehub.model.exceptions.UserNotAuthorizedException;
import org.gcube.common.storagehub.model.items.Item;
import org.gcube.common.storagehub.model.items.SharedFolder;
import org.gcube.data.access.storagehub.AuthorizationChecker;
import org.gcube.common.storagehub.model.types.SHUBUser;
import org.gcube.data.access.storagehub.Constants;
import org.gcube.data.access.storagehub.PathUtil;
import org.gcube.data.access.storagehub.StorageHubAppllicationManager;
import org.gcube.data.access.storagehub.Utils;
import org.gcube.data.access.storagehub.exception.MyAuthException;
import org.gcube.data.access.storagehub.handlers.CredentialHandler;
import org.gcube.data.access.storagehub.handlers.GroupHandler;
import org.gcube.data.access.storagehub.handlers.TrashHandler;
import org.gcube.data.access.storagehub.handlers.UnshareHandler;
import org.gcube.data.access.storagehub.handlers.items.builders.FolderCreationParameters;
import org.gcube.data.access.storagehub.StorageHubApplicationManager;
import org.gcube.data.access.storagehub.repository.StoragehubRepository;
import org.gcube.data.access.storagehub.services.delegates.UserManagerDelegate;
import org.gcube.smartgears.annotations.ManagedBy;
import org.gcube.smartgears.utils.InnerMethodName;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.webcohesion.enunciate.metadata.rs.RequestHeader;
import com.webcohesion.enunciate.metadata.rs.RequestHeaders;
import jakarta.inject.Inject;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.DELETE;
import jakarta.ws.rs.FormParam;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.PUT;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
@Path("users")
@ManagedBy(StorageHubAppllicationManager.class)
@ManagedBy(StorageHubApplicationManager.class)
@RequestHeaders({
@RequestHeader(name = "Authorization", description = "Bearer token, see https://dev.d4science.org/how-to-access-resources"), })
public class UserManager {
private static final String INFRASTRUCTURE_MANAGER_ROLE = "Infrastructure-Manager";
@Context ServletContext context;
private static final Logger log = LoggerFactory.getLogger(UserManager.class);
RepositoryInitializer repository = StorageHubAppllicationManager.repository;
private final StoragehubRepository repository = StoragehubRepository.repository;
@Inject
UnshareHandler unshareHandler;
UserManagerDelegate userHandler;
@Inject
AuthorizationChecker authChecker;
@Inject
TrashHandler trashHandler;
@Inject
GroupHandler groupHandler;
@Inject
PathUtil pathUtil;
@GET
@Path("")
@Produces(MediaType.APPLICATION_JSON)
public List<String> getUsers(){
InnerMethodName.instance.set("getUsers");
public List<SHUBUser> getUsers() {
InnerMethodName.set("getUsers");
JackrabbitSession session = null;
List<String> users = null;
try {
session = (JackrabbitSession) repository.getRepository().login(CredentialHandler.getAdminCredentials(context));
Iterator<Authorizable> result = session.getUserManager().findAuthorizables(new Query() {
@Override
public <T> void build(QueryBuilder<T> builder) {
builder.setSelector(User.class);
}
});
Set<String> usersSet= new HashSet<>();
String adminUser = context.getInitParameter(Constants.ADMIN_PARAM_NAME);
while (result.hasNext()) {
Authorizable user = result.next();
log.debug("user {} found",user.getPrincipal().getName());
if (user.getPrincipal().getName().equals(adminUser)) continue;
usersSet.add(user.getPrincipal().getName());
}
users = new ArrayList<>(usersSet);
Collections.sort(users);
}catch(Exception e) {
session = (JackrabbitSession) repository.getRepository().login(Constants.JCR_CREDENTIALS);
return userHandler.getAllUsers(session);
} catch (Throwable e) {
log.error("jcr error getting users", e);
GXOutboundErrorResponse.throwException(new BackendGenericError(e));
} finally {
if (session!=null)
if (session != null)
session.logout();
}
return users;
return null;
}
@GET
@Path("{user}")
public String getUser(@PathParam("user") String user){
public SHUBUser getUser(@PathParam("user") String user) {
InnerMethodName.instance.set("getUser");
InnerMethodName.set("getUser");
JackrabbitSession session = null;
try {
session = (JackrabbitSession) repository.getRepository().login(CredentialHandler.getAdminCredentials(context));
org.apache.jackrabbit.api.security.user.UserManager usrManager = session.getUserManager();
Authorizable authorizable = usrManager.getAuthorizable(user);
if (authorizable != null && !authorizable.isGroup())
return authorizable.getPrincipal().getName();
log.debug("user {} not found", user);
}catch(Exception e) {
session = (JackrabbitSession) repository.getRepository().login(Constants.JCR_CREDENTIALS);
userHandler.getUser(session, user);
} catch (StorageHubException se) {
log.error("error getting user", se);
GXOutboundErrorResponse.throwException(se);
} catch (Exception e) {
log.error("jcr error getting user", e);
GXOutboundErrorResponse.throwException(new BackendGenericError(e));
} finally {
if (session!=null)
if (session != null)
session.logout();
}
@ -163,201 +100,114 @@ public class UserManager {
@POST
@Path("")
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
@AuthorizationControl(allowedRoles={INFRASTRUCTURE_MANAGER_ROLE}, exception=MyAuthException.class)
public String createUser(@FormParam("user") String user, @FormParam("password") String password){
@AuthorizationControl(allowedRoles = { INFRASTRUCTURE_MANAGER_ROLE })
public String createUser(@FormParam("user") String user, @FormParam("password") String password) {
InnerMethodName.instance.set("createUser");
InnerMethodName.set("createUser");
JackrabbitSession session = null;
String userId = null;
try {
session = (JackrabbitSession) repository.getRepository().login(CredentialHandler.getAdminCredentials(context));
session = (JackrabbitSession) repository.getRepository().login(Constants.JCR_CREDENTIALS);
userId = userHandler.createUser(session, user, password);
org.apache.jackrabbit.api.security.user.UserManager usrManager = session.getUserManager();
User createdUser = usrManager.createUser(user, password);
userId = createdUser.getID();
Node homeNode = session.getNode("/Home");
Node userHome = homeNode.addNode(user, "nthl:home");
userHome.setProperty(Constants.HOME_VERSION_PROP, 1l);
//creating workspace folder
FolderCreationParameters wsFolderParameters = FolderCreationParameters.builder().name(Constants.WORKSPACE_ROOT_FOLDER_NAME).description("workspace of "+user).author(user).on(userHome.getIdentifier()).with(session).build();
Utils.createFolderInternally(wsFolderParameters, null);
//creating thrash folder
FolderCreationParameters trashFolderParameters = FolderCreationParameters.builder().name(Constants.TRASH_ROOT_FOLDER_NAME).description("trash of "+user).author(user).on(userHome.getIdentifier()).with(session).build();
Utils.createFolderInternally(trashFolderParameters, null);
//creating Vre container folder
FolderCreationParameters vreFolderParameters = FolderCreationParameters.builder().name(Constants.PERSONAL_VRES_FOLDER_PARENT_NAME).description("vre folder container of "+user).author(user).on(userHome.getIdentifier()).with(session).build();
Utils.createFolderInternally(vreFolderParameters, null);
//creating inbox folder
FolderCreationParameters inboxFolderParameters = FolderCreationParameters.builder().name(Constants.INBOX_FOLDER_NAME).description("inbox of "+user).author(user).on(userHome.getIdentifier()).with(session).build();
Utils.createFolderInternally(inboxFolderParameters, null);
//creating outbox folder
FolderCreationParameters outboxFolderParameters = FolderCreationParameters.builder().name(Constants.OUTBOX_FOLDER_NAME).description("outbox of "+user).author(user).on(userHome.getIdentifier()).with(session).build();
Utils.createFolderInternally(outboxFolderParameters, null);
session.save();
}catch(StorageHubException she ){
} catch (StorageHubException she) {
log.error(she.getErrorMessage(), she);
GXOutboundErrorResponse.throwException(she, Response.Status.fromStatusCode(she.getStatus()));
}catch(RepositoryException re ){
} catch (RepositoryException re) {
log.error("jcr error creating item", re);
GXOutboundErrorResponse.throwException(new BackendGenericError("jcr error creating item", re));
} finally {
if (session!=null)
if (session != null)
session.logout();
}
return userId;
}
@PUT
@Path("{user}")
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
@AuthorizationControl(allowedRoles = { INFRASTRUCTURE_MANAGER_ROLE })
public String updateHomeUserToLatestVersion(@PathParam("user") String user) {
InnerMethodName.set("updateHomeUserToLatestVersion");
JackrabbitSession session = null;
String userId = null;
try {
session = (JackrabbitSession) repository.getRepository().login(Constants.JCR_CREDENTIALS);
userId = userHandler.updateHomeUserToLatestVersion(session, userId);
session.save();
} catch (StorageHubException she) {
log.error(she.getErrorMessage(), she);
GXOutboundErrorResponse.throwException(she, Response.Status.fromStatusCode(she.getStatus()));
} catch (RepositoryException re) {
log.error("jcr error creating item", re);
GXOutboundErrorResponse.throwException(new BackendGenericError("jcr error creating item", re));
} finally {
if (session != null)
session.logout();
}
return userId;
}
@DELETE
@Path("{user}")
@AuthorizationControl(allowedRoles={INFRASTRUCTURE_MANAGER_ROLE}, exception=MyAuthException.class)
public String deleteUser(@PathParam("user") final String user){
@AuthorizationControl(allowedRoles = { INFRASTRUCTURE_MANAGER_ROLE })
public String deleteUser(@PathParam("user") final String user) {
InnerMethodName.instance.set("deleteUser");
InnerMethodName.set("deleteUser");
JackrabbitSession session = null;
try {
session = (JackrabbitSession) repository.getRepository().login(CredentialHandler.getAdminCredentials(context));
session = (JackrabbitSession) repository.getRepository().login(Constants.JCR_CREDENTIALS);
org.apache.jackrabbit.api.security.user.UserManager usrManager = session.getUserManager();
User authorizable = (User) usrManager.getAuthorizable(new PrincipalImpl(user));
if (authorizable!=null)
removeUserFromBelongingGroup(session, authorizable, usrManager);
else log.warn("user was already deleted from jackrabbit, trying to delete folders");
unshareUsersFolders(session, user);
removeUserHomeAndDeleteFiles(session, user);
//FINALIZE user removal
if (authorizable!=null && !authorizable.isGroup()) {
log.info("removing user {}", user);
authorizable.remove();
} else log.warn("the user {} was already deleted, it should never happen", user);
userHandler.deleteUser(session, user);
session.save();
}catch(StorageHubException she ){
} catch (StorageHubException she) {
log.error(she.getErrorMessage(), she);
GXOutboundErrorResponse.throwException(she, Response.Status.fromStatusCode(she.getStatus()));
}catch(RepositoryException re ){
} catch (RepositoryException re) {
log.error("jcr error creating item", re);
GXOutboundErrorResponse.throwException(new BackendGenericError("jcr error creating item", re));
} finally {
if (session!=null)
if (session != null)
session.logout();
}
return user;
}
private void removeUserFromBelongingGroup(JackrabbitSession session, User authorizable, org.apache.jackrabbit.api.security.user.UserManager usrManager) throws RepositoryException, StorageHubException {
Iterator<Authorizable> groups = session.getUserManager().findAuthorizables(new Query() {
@GET
@Path("{user}/groups")
@Produces(MediaType.APPLICATION_JSON)
public List<String> getGroupsPerUser(@PathParam("user") final String user) {
@Override
public <T> void build(QueryBuilder<T> builder) {
builder.setSelector(Group.class);
}
});
String user = authorizable.getPrincipal().getName();
while(groups.hasNext()) {
Authorizable group = groups.next();
log.info("group found {}", group.getPrincipal().getName() );
if (group.isGroup() && ((Group)group).isMember(authorizable)) {
boolean success = groupHandler.removeUserFromGroup(group.getPrincipal().getName(), user, session);
log.warn("user {} {} removed from vre {}",user,success?"":"not" ,group.getPrincipal().getName());
}
}
}
private void unshareUsersFolders(JackrabbitSession session, String user){
InnerMethodName.set("getGroupsPerUser");
JackrabbitSession session = null;
List<String> groups = new ArrayList<>();
try {
session = (JackrabbitSession) repository.getRepository().login(Constants.JCR_CREDENTIALS);
Node sharedFolderNode = session.getNode(Constants.SHARED_FOLDER_PATH);
Predicate<Node> sharedWithUserChecker = new Predicate<Node>() {
@Override
public boolean test(Node t) {
try {
authChecker.checkReadAuthorizationControl(t.getSession(), user, t.getIdentifier());
return true;
} catch (UserNotAuthorizedException | BackendGenericError | RepositoryException e) {
return false;
}
}
};
List<SharedFolder> items = Utils.getItemList(sharedWithUserChecker, sharedFolderNode, Excludes.ALL, null, false, SharedFolder.class);
log.debug(" Shared folder to unshare found are {}", items.size());
for (SharedFolder item: items) {
String title = item.getTitle();
log.debug("in list folder name {} with title {} and path {} ",item.getName(), title, item.getPath());
if (item.isPublicItem() && !item.getUsers().getMap().containsKey(user)) continue;
if (item.isVreFolder()) continue;
log.info("removing sharing for folder name {} with title {} and path {} ",item.getName(), title, item.getPath());
String owner = item.getOwner();
Set<String> usersToUnshare= owner.equals(user)? Collections.emptySet():Collections.singleton(user);
try {
unshareHandler.unshareForRemoval(session, usersToUnshare, session.getNodeByIdentifier(item.getId()), user);
}catch (Throwable e) {
log.warn("error unsharing folder with title '{}' and id {} ", title, item.getId(), e);
}
}
} catch (Throwable t) {
log.warn("error getting folder shared with {}",user, t);
userHandler.getGroupsPerUser(session, user);
} catch (RepositoryException re) {
log.error("jcr error creating item", re);
GXOutboundErrorResponse.throwException(new BackendGenericError("jcr error creating item", re));
} finally {
if (session != null)
session.logout();
}
return groups;
}
private void removeUserHomeAndDeleteFiles(JackrabbitSession session, String user) throws RepositoryException, StorageHubException {
org.gcube.common.storagehub.model.Path homePath = pathUtil.getHome(user);
org.gcube.common.storagehub.model.Path workspacePath = pathUtil.getWorkspacePath(user);
org.gcube.common.storagehub.model.Path trashPath = pathUtil.getTrashPath(user, session);
try {
Node workspaceNode = session.getNode(workspacePath.toPath());
List<Item> workspaceItems = Utils.getItemList(workspaceNode, Excludes.GET_ONLY_CONTENT, null, true, null).stream().filter(i -> !i.isShared()).collect(Collectors.toList());
trashHandler.removeOnlyNodesContent(session, workspaceItems);
} catch (PathNotFoundException e) {
log.warn("{} workspace dir {} was already deleted", user, homePath.toPath());
}
try {
Node trashNode = session.getNode(trashPath.toPath());
List<Item> trashItems = Utils.getItemList(trashNode, Excludes.ALL, null, true, null);
trashHandler.removeOnlyNodesContent(session, trashItems);
} catch (PathNotFoundException e) {
log.warn("{} trash dir {} was already deleted", user, homePath.toPath());
}
try {
Node homeNode = session.getNode(homePath.toPath());
homeNode.remove();
} catch (PathNotFoundException e) {
log.warn("{} home dir {} was already deleted", user, homePath.toPath());
}
}
}

View File

@ -1,25 +1,12 @@
package org.gcube.data.access.storagehub.services;
import java.io.InputStream;
import java.util.Collections;
import java.util.List;
import javax.enterprise.context.RequestScoped;
import javax.inject.Inject;
import javax.jcr.Node;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.servlet.ServletContext;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.FormParam;
import javax.ws.rs.GET;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import org.apache.jackrabbit.api.JackrabbitSession;
import org.gcube.common.gxrest.response.outbound.GXOutboundErrorResponse;
@ -32,128 +19,205 @@ import org.gcube.common.storagehub.model.exceptions.StorageHubException;
import org.gcube.common.storagehub.model.exceptions.UserNotAuthorizedException;
import org.gcube.common.storagehub.model.items.FolderItem;
import org.gcube.common.storagehub.model.items.Item;
import org.gcube.common.storagehub.model.items.SharedFolder;
import org.gcube.common.storagehub.model.items.TrashItem;
import org.gcube.common.storagehub.model.items.nodes.PayloadBackend;
import org.gcube.common.storagehub.model.service.ItemList;
import org.gcube.common.storagehub.model.service.ItemWrapper;
import org.gcube.common.storagehub.model.storages.MetaInfo;
import org.gcube.common.storagehub.model.storages.StorageBackend;
import org.gcube.common.storagehub.model.storages.StorageBackendFactory;
import org.gcube.data.access.storagehub.AuthorizationChecker;
import org.gcube.data.access.storagehub.Constants;
import org.gcube.data.access.storagehub.PathUtil;
import org.gcube.data.access.storagehub.Range;
import org.gcube.data.access.storagehub.StorageHubAppllicationManager;
import org.gcube.data.access.storagehub.StorageHubApplicationManager;
import org.gcube.data.access.storagehub.Utils;
import org.gcube.data.access.storagehub.handlers.CredentialHandler;
import org.gcube.data.access.storagehub.handlers.PublicLinkHandler;
import org.gcube.data.access.storagehub.handlers.TrashHandler;
import org.gcube.data.access.storagehub.handlers.items.Item2NodeConverter;
import org.gcube.data.access.storagehub.handlers.items.Node2ItemConverter;
import org.gcube.data.access.storagehub.handlers.items.builders.FolderCreationParameters;
import org.gcube.data.access.storagehub.handlers.plugins.FolderPluginHandler;
import org.gcube.data.access.storagehub.handlers.plugins.StorageBackendHandler;
import org.gcube.data.access.storagehub.handlers.vres.VRE;
import org.gcube.data.access.storagehub.handlers.vres.VREManager;
import org.gcube.data.access.storagehub.query.sql2.evaluators.Evaluators;
import org.gcube.data.access.storagehub.repository.StoragehubRepository;
import org.gcube.data.access.storagehub.storage.backend.impl.GCubeVolatileStorageBackendFactory;
import org.gcube.smartgears.annotations.ManagedBy;
import org.gcube.smartgears.utils.InnerMethodName;
import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
import org.glassfish.jersey.media.multipart.FormDataParam;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.webcohesion.enunciate.metadata.rs.RequestHeader;
import com.webcohesion.enunciate.metadata.rs.RequestHeaders;
import jakarta.enterprise.context.RequestScoped;
import jakarta.inject.Inject;
import jakarta.servlet.ServletContext;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.DELETE;
import jakarta.ws.rs.FormParam;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.PUT;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.QueryParam;
import jakarta.ws.rs.core.Context;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
@Path("/")
@ManagedBy(StorageHubAppllicationManager.class)
public class WorkspaceManager extends Impersonable{
@ManagedBy(StorageHubApplicationManager.class)
@RequestHeaders({
@RequestHeader(name = "Authorization", description = "Bearer token, see https://dev.d4science.org/how-to-access-resources"), })
public class WorkspaceManager extends Impersonable {
private static final Logger log = LoggerFactory.getLogger(WorkspaceManager.class);
RepositoryInitializer repository = StorageHubAppllicationManager.repository;
private final StoragehubRepository repository = StoragehubRepository.repository;
@Inject
Evaluators evaluator;
@Inject
PathUtil pathUtil;
@Inject
VREManager vreManager;
@Context
@Context
ServletContext context;
@Inject
AuthorizationChecker authChecker;
@Inject
TrashHandler trashHandler;
@RequestScoped
@QueryParam("exclude")
private List<String> excludes = Collections.emptyList();
@Inject Node2ItemConverter node2Item;
@Inject Item2NodeConverter item2Node;
@Inject
FolderPluginHandler folderHandler;
TrashHandler trashHandler;
@Inject
StorageBackendHandler storageBackendHandler;
@Inject
PublicLinkHandler publicLinkHandler;
@RequestScoped
@QueryParam("exclude")
private List<String> excludes = Collections.emptyList();
@Inject
Node2ItemConverter node2Item;
@Inject
Item2NodeConverter item2Node;
@Path("/")
@GET
@Produces(MediaType.APPLICATION_JSON)
public ItemWrapper<Item> getWorkspace(@QueryParam("relPath") String relPath){
InnerMethodName.instance.set("getWorkspace");
public ItemWrapper<Item> getWorkspace(@QueryParam("relPath") String relPath) {
InnerMethodName.set("getWorkspace");
Session ses = null;
org.gcube.common.storagehub.model.Path absolutePath;
if (relPath==null)
if (relPath == null)
absolutePath = pathUtil.getWorkspacePath(currentUser);
else absolutePath = Paths.append(pathUtil.getWorkspacePath(currentUser), relPath);
else
absolutePath = Paths.append(pathUtil.getWorkspacePath(currentUser), relPath);
Item toReturn = null;
try{
ses = repository.getRepository().login(CredentialHandler.getAdminCredentials(context));
//TODO: remove when all user will have TRASH
try {
ses = repository.getRepository().login(Constants.JCR_CREDENTIALS);
// TODO: remove when all user will have TRASH
org.gcube.common.storagehub.model.Path trashPath = pathUtil.getTrashPath(currentUser, ses);
if (!ses.nodeExists(trashPath.toPath())) {
Node wsNode = ses.getNode(pathUtil.getWorkspacePath(currentUser).toPath());
FolderCreationParameters trashFolderParameters = FolderCreationParameters.builder().name(Constants.TRASH_ROOT_FOLDER_NAME)
.description("trash of "+currentUser)
FolderCreationParameters trashFolderParameters = FolderCreationParameters.builder()
.name(Constants.TRASH_ROOT_FOLDER_NAME).description("trash of " + currentUser)
.author(currentUser).on(wsNode.getIdentifier()).with(ses).build();
Utils.createFolderInternally(trashFolderParameters, null);
Utils.createFolderInternally(trashFolderParameters, null, true);
ses.save();
}
Node node = ses.getNode(absolutePath.toPath());
authChecker.checkReadAuthorizationControl(ses, currentUser, node.getIdentifier());
toReturn = node2Item.getItem(node, excludes);
}catch(RepositoryException re ){
} catch (RepositoryException re) {
log.error("jcr error getting workspace item", re);
GXOutboundErrorResponse.throwException(new BackendGenericError(re));
}catch(StorageHubException she ){
} catch (StorageHubException she) {
log.error(she.getErrorMessage(), she);
GXOutboundErrorResponse.throwException(she, Response.Status.fromStatusCode(she.getStatus()));
}finally{
if (ses!=null)
} finally {
if (ses != null)
ses.logout();
}
return new ItemWrapper<Item>(toReturn);
}
/**
* Uploads a file in the volatile area returning a public link
*
* @param id
* @param name
* @param description
* @param stream
* @param fileDetail
* @return
*/
@POST
@Consumes(MediaType.MULTIPART_FORM_DATA)
@Path("volatile")
public String uploadVolatileFile(@FormDataParam("file") InputStream stream,
@FormDataParam("file") FormDataContentDisposition fileDetail) {
InnerMethodName.set("uploadToVolatileArea");
log.info("uploading file {} of size {} to volatile area ({} - {})", fileDetail.getFileName(),
fileDetail.getSize(), fileDetail.getName(), fileDetail.getParameters().toString());
String toReturn = null;
try {
long size = fileDetail.getSize();
PayloadBackend payloadBackend = new PayloadBackend(GCubeVolatileStorageBackendFactory.NAME, null);
StorageBackendFactory sbf = storageBackendHandler.get(payloadBackend);
StorageBackend sb = sbf.create(payloadBackend);
log.info("UPLOAD: call started with file size {}", size);
MetaInfo info = sb.upload(stream, null, fileDetail.getFileName(), currentUser);
log.debug("UPLOAD: call finished");
toReturn = publicLinkHandler.getForVolatile(info.getStorageId(), GCubeVolatileStorageBackendFactory.NAME,
context);
} catch (StorageHubException se) {
log.error("error uploading file to volatile area", se);
GXOutboundErrorResponse.throwException(se);
} catch (Throwable e) {
log.error("error uploading file to volatile area", e);
GXOutboundErrorResponse.throwException(new BackendGenericError(e));
}
return toReturn;
}
@Path("vrefolder")
@GET
@Produces(MediaType.APPLICATION_JSON)
public ItemWrapper<Item> getVreRootFolder(){
InnerMethodName.instance.set("getVreRootFolder");
public ItemWrapper<Item> getVreRootFolder() {
InnerMethodName.set("getVreRootFolder");
JackrabbitSession ses = null;
Item vreItem = null;
try {
ses = (JackrabbitSession) repository.getRepository().login(CredentialHandler.getAdminCredentials(context));
ses = (JackrabbitSession) repository.getRepository().login(Constants.JCR_CREDENTIALS);
vreItem = vreManager.getVreFolderItem(ses, currentUser, excludes).getVreFolder();
}catch(RepositoryException re ){
} catch (RepositoryException re) {
log.error("jcr error getting vrefolder", re);
GXOutboundErrorResponse.throwException(new BackendGenericError(re));
}catch(StorageHubException she ){
} catch (StorageHubException she) {
log.error(she.getErrorMessage(), she);
GXOutboundErrorResponse.throwException(she, Response.Status.fromStatusCode(she.getStatus()));
}finally{
if (ses!=null)
} finally {
if (ses != null)
ses.logout();
}
return new ItemWrapper<Item>(vreItem);
@ -162,163 +226,161 @@ public class WorkspaceManager extends Impersonable{
@Path("vrefolder/recents")
@GET
@Produces(MediaType.APPLICATION_JSON)
public ItemList getVreFolderRecentsDocument(){
InnerMethodName.instance.set("getVreFolderRecents");
public ItemList getVreFolderRecentsDocument() {
InnerMethodName.set("getVreFolderRecents");
JackrabbitSession ses = null;
List<Item> recentItems = Collections.emptyList();
try{
ses = (JackrabbitSession) repository.getRepository().login(CredentialHandler.getAdminCredentials(context));
try {
ses = (JackrabbitSession) repository.getRepository().login(Constants.JCR_CREDENTIALS);
VRE vre = vreManager.getVreFolderItem(ses, currentUser, excludes);
log.trace("VRE retrieved {}",vre.getVreFolder().getTitle());
log.trace("VRE retrieved {}", vre.getVreFolder().getTitle());
recentItems = vre.getRecents();
log.trace("recents retrieved {}",vre.getVreFolder().getTitle());
log.trace("recents retrieved {}", vre.getVreFolder().getTitle());
return new ItemList(recentItems);
}catch(RepositoryException re ){
} catch (RepositoryException re) {
log.error("jcr error getting recents", re);
GXOutboundErrorResponse.throwException(new BackendGenericError(re));
}catch(StorageHubException she ){
} catch (StorageHubException she) {
log.error(she.getErrorMessage(), she);
GXOutboundErrorResponse.throwException(she, Response.Status.fromStatusCode(she.getStatus()));
}finally{
if (ses!=null)
} finally {
if (ses != null)
ses.logout();
}
return new ItemList(recentItems);
}
@Path("trash")
@GET
@Produces(MediaType.APPLICATION_JSON)
public ItemWrapper<Item> getTrashRootFolder(){
InnerMethodName.instance.set("getTrashRootFolder");
public ItemWrapper<Item> getTrashRootFolder() {
InnerMethodName.set("getTrashRootFolder");
Session ses = null;
Item item = null;
try{
try {
long start = System.currentTimeMillis();
ses = repository.getRepository().login(CredentialHandler.getAdminCredentials(context));
ses = repository.getRepository().login(Constants.JCR_CREDENTIALS);
org.gcube.common.storagehub.model.Path trashPath = pathUtil.getTrashPath(currentUser, ses);
log.info("time to connect to repo {}",(System.currentTimeMillis()-start));
log.info("time to connect to repo {}", (System.currentTimeMillis() - start));
Node folder = ses.getNode(trashPath.toPath());
item = node2Item.getItem(folder, excludes);
}catch(RepositoryException re ){
} catch (RepositoryException re) {
log.error("jcr error getting trash", re);
GXOutboundErrorResponse.throwException(new BackendGenericError(re));
}catch(StorageHubException she ){
} catch (StorageHubException she) {
log.error(she.getErrorMessage(), she);
GXOutboundErrorResponse.throwException(she, Response.Status.fromStatusCode(she.getStatus()));
}finally{
if (ses!=null)
} finally {
if (ses != null)
ses.logout();
}
return new ItemWrapper<Item>(item);
}
@Path("trash/empty")
@DELETE
public String emptyTrash(){
InnerMethodName.instance.set("emptyTrash");
public String emptyTrash() {
InnerMethodName.set("emptyTrash");
Session ses = null;
String toReturn = null;
try{
ses = repository.getRepository().login(CredentialHandler.getAdminCredentials(context));
try {
ses = repository.getRepository().login(Constants.JCR_CREDENTIALS);
org.gcube.common.storagehub.model.Path trashPath = pathUtil.getTrashPath(currentUser, ses);
Node trashNode = ses.getNode(trashPath.toPath());
List<Item> itemsToDelete = Utils.getItemList(trashNode, Excludes.ALL, null, true, null);
trashHandler.removeNodes(ses, itemsToDelete);
toReturn = trashNode.getIdentifier();
}catch(RepositoryException re ){
} catch (RepositoryException re) {
log.error("jcr error emptying trash", re);
GXOutboundErrorResponse.throwException(new BackendGenericError(re));
}catch(StorageHubException she ){
} catch (StorageHubException she) {
log.error(she.getErrorMessage(), she);
GXOutboundErrorResponse.throwException(she, Response.Status.fromStatusCode(she.getStatus()));
}finally{
if (ses!=null)
} finally {
if (ses != null)
ses.logout();
}
return toReturn;
}
@PUT
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
@Path("trash/restore")
public String restoreItem(@FormParam("trashedItemId") String trashedItemId,@FormParam("destinationId") String destinationFolderId){
InnerMethodName.instance.set("restoreItem");
public String restoreItem(@FormParam("trashedItemId") String trashedItemId,
@FormParam("destinationId") String destinationFolderId) {
InnerMethodName.set("restoreItem");
Session ses = null;
String toReturn = null;
try{
try {
log.info("restoring node with id {}", trashedItemId);
ses = repository.getRepository().login(CredentialHandler.getAdminCredentials(context));
ses = repository.getRepository().login(Constants.JCR_CREDENTIALS);
final Node nodeToRestore = ses.getNodeByIdentifier(trashedItemId);
Item itemToRestore = node2Item.getItem(nodeToRestore, Excludes.ALL);
if (!(itemToRestore instanceof TrashItem))
throw new InvalidItemException("Only trash items can be restored");
org.gcube.common.storagehub.model.Path trashPath = pathUtil.getTrashPath(currentUser, ses);
if (!itemToRestore.getPath().startsWith(trashPath.toPath()))
throw new UserNotAuthorizedException("this item is not in the user "+currentUser+" trash");
throw new UserNotAuthorizedException("this item is not in the user " + currentUser + " trash");
Item destinationItem = null;
if (destinationFolderId!=null ) {
if (destinationFolderId != null) {
destinationItem = node2Item.getItem(ses.getNodeByIdentifier(destinationFolderId), Excludes.ALL);
if (!(destinationItem instanceof FolderItem))
if (!(destinationItem instanceof FolderItem))
throw new InvalidCallParameters("destintation item is not a folder");
toReturn = trashHandler.restoreItem(ses, (TrashItem)itemToRestore, (FolderItem) destinationItem, currentUser);
} else
toReturn = trashHandler.restoreItem(ses, (TrashItem)itemToRestore, null, currentUser);
}catch(RepositoryException re ){
log.error("error restoring item with id {}",trashedItemId, re);
toReturn = trashHandler.restoreItem(ses, (TrashItem) itemToRestore, (FolderItem) destinationItem,
currentUser);
} else
toReturn = trashHandler.restoreItem(ses, (TrashItem) itemToRestore, null, currentUser);
} catch (RepositoryException re) {
log.error("error restoring item with id {}", trashedItemId, re);
GXOutboundErrorResponse.throwException(new BackendGenericError(re));
}catch(StorageHubException she ){
} catch (StorageHubException she) {
log.error(she.getErrorMessage(), she);
GXOutboundErrorResponse.throwException(she, Response.Status.fromStatusCode(she.getStatus()));
}finally{
if (ses!=null) {
} finally {
if (ses != null) {
ses.logout();
}
}
return toReturn;
}
@Path("vrefolders")
@GET
@Produces(MediaType.APPLICATION_JSON)
public ItemList getVreFolders(){
InnerMethodName.instance.set("getVreFolders");
public ItemList getVreFolders() {
InnerMethodName.set("getVreFolders");
Session ses = null;
List<? extends Item> toReturn = null;
org.gcube.common.storagehub.model.Path vrePath = null;
try{
ses = repository.getRepository().login(CredentialHandler.getAdminCredentials(context));
try {
ses = repository.getRepository().login(Constants.JCR_CREDENTIALS);
vrePath = pathUtil.getVREsPath(currentUser, ses);
log.info("vres folder path is {}",vrePath.toPath());
log.info("vres folder path is {}", vrePath.toPath());
toReturn = Utils.getItemList(ses.getNode(vrePath.toPath()) , excludes, null, false, null);
}catch(RepositoryException re ){
log.error("error reading the node children of {}",vrePath, re);
toReturn = Utils.getItemList(ses.getNode(vrePath.toPath()), excludes, null, false, null);
} catch (RepositoryException re) {
log.error("error reading the node children of {}", vrePath, re);
GXOutboundErrorResponse.throwException(new BackendGenericError(re));
}catch(StorageHubException she ){
} catch (StorageHubException she) {
log.error(she.getErrorMessage(), she);
GXOutboundErrorResponse.throwException(she, Response.Status.fromStatusCode(she.getStatus()));
}finally{
if (ses!=null)
} finally {
if (ses != null)
ses.logout();
}
@ -328,45 +390,94 @@ public class WorkspaceManager extends Impersonable{
@Path("vrefolders/paged")
@GET
@Produces(MediaType.APPLICATION_JSON)
public ItemList getVreFoldersPaged(@QueryParam("start") Integer start, @QueryParam("limit") Integer limit){
InnerMethodName.instance.set("getVreFoldersPaged");
public ItemList getVreFoldersPaged(@QueryParam("start") Integer start, @QueryParam("limit") Integer limit) {
InnerMethodName.set("getVreFoldersPaged");
Session ses = null;
org.gcube.common.storagehub.model.Path vrePath = null;
List<? extends Item> toReturn = null;
try{
ses = repository.getRepository().login(CredentialHandler.getAdminCredentials(context));
try {
ses = repository.getRepository().login(Constants.JCR_CREDENTIALS);
vrePath = pathUtil.getVREsPath(currentUser, ses);
toReturn = Utils.getItemList(ses.getNode(vrePath.toPath()) , excludes, new Range(start, limit), false, null);
}catch(RepositoryException re ){
log.error("(paged) error reading the node children of {}",vrePath, re);
toReturn = Utils.getItemList(ses.getNode(vrePath.toPath()), excludes, new Range(start, limit), false, null);
} catch (RepositoryException re) {
log.error("(paged) error reading the node children of {}", vrePath, re);
GXOutboundErrorResponse.throwException(new BackendGenericError(re));
}catch(StorageHubException she ){
} catch (StorageHubException she) {
log.error(she.getErrorMessage(), she);
GXOutboundErrorResponse.throwException(she, Response.Status.fromStatusCode(she.getStatus()));
}finally{
if (ses!=null)
} finally {
if (ses != null)
ses.logout();
}
return new ItemList(toReturn);
}
/*
* @Path("shared-by-me")
*
* @GET
*
* @Produces(MediaType.APPLICATION_JSON) public ItemList getMySharedFolders(){
* InnerMethodName.set("getMySharedFolders"); Session ses = null; List<? extends
* Item> toReturn = null; org.gcube.common.storagehub.model.Path sharedPath =
* null; try{ ses = repository.getRepository().login(Constants.JCR_CREDENTIALS);
* sharedPath = pathUtil.getMySharedPath(currentUser);
* log.info("my shared folder path is folder path is {}",sharedPath.toPath());
*
* toReturn = Utils.getItemList(ses.getNode(sharedPath.toPath()) , excludes,
* null, false, SharedFolder.class); }catch(RepositoryException re ){
* log.error("error reading my shared folder ({})",sharedPath, re);
* GXOutboundErrorResponse.throwException(new BackendGenericError(re));
* }catch(StorageHubException she ){ log.error(she.getErrorMessage(), she);
* GXOutboundErrorResponse.throwException(she,
* Response.Status.fromStatusCode(she.getStatus())); }finally{ if (ses!=null)
* ses.logout(); }
*
* return new ItemList(toReturn); }
*/
@Path("shared-with-me")
@GET
@Produces(MediaType.APPLICATION_JSON)
public ItemList getSharedWithMeFolders() {
InnerMethodName.set("getSharedWithMeFolders");
Session ses = null;
List<? extends Item> toReturn = null;
org.gcube.common.storagehub.model.Path sharedPath = null;
try {
ses = repository.getRepository().login(Constants.JCR_CREDENTIALS);
sharedPath = pathUtil.getSharedWithMePath(currentUser);
log.info("vres folder path is {}", sharedPath.toPath());
toReturn = Utils.getItemList(ses.getNode(sharedPath.toPath()), excludes, null, false, SharedFolder.class);
} catch (RepositoryException re) {
log.error("error reading shared with me folder ({})", sharedPath, re);
GXOutboundErrorResponse.throwException(new BackendGenericError(re));
} catch (StorageHubException she) {
log.error(she.getErrorMessage(), she);
GXOutboundErrorResponse.throwException(she, Response.Status.fromStatusCode(she.getStatus()));
} finally {
if (ses != null)
ses.logout();
}
return new ItemList(toReturn);
}
@Path("count")
@GET
public String getTotalItemsCount(){
InnerMethodName.instance.set("getTotalItemsCount");
return folderHandler.getDefault().getStorageBackend().getTotalItemsCount();
public String getTotalItemsCount() {
InnerMethodName.set("getTotalItemsCount");
return "1203";
}
@Path("size")
@GET
public String getTotalVolume(){
InnerMethodName.instance.set("getTotalSize");
return folderHandler.getDefault().getStorageBackend().getTotalSizeStored();
public String getTotalVolume() {
InnerMethodName.set("getTotalSize");
return "120300000";
}
}

View File

@ -2,86 +2,169 @@ package org.gcube.data.access.storagehub.services.admin;
import static org.gcube.data.access.storagehub.Roles.INFRASTRUCTURE_MANAGER_ROLE;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.PrintWriter;
import java.io.StringReader;
import java.io.StringWriter;
import java.util.HashMap;
import java.util.UUID;
import javax.inject.Inject;
import javax.jcr.Node;
import javax.servlet.ServletContext;
import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.jcr.Session;
import org.apache.cxf.io.ReaderInputStream;
import org.apache.jackrabbit.api.JackrabbitSession;
import org.gcube.common.authorization.control.annotations.AuthorizationControl;
import org.gcube.common.authorization.library.AuthorizedTasks;
import org.gcube.common.authorization.library.provider.AuthorizationProvider;
import org.gcube.common.security.AuthorizedTasks;
import org.gcube.common.security.providers.SecretManagerProvider;
import org.gcube.common.storagehub.model.Paths;
import org.gcube.common.storagehub.model.exporter.DumpData;
import org.gcube.data.access.storagehub.Constants;
import org.gcube.data.access.storagehub.PathUtil;
import org.gcube.data.access.storagehub.StorageHubAppllicationManager;
import org.gcube.data.access.storagehub.accounting.AccountingHandler;
import org.gcube.data.access.storagehub.exception.MyAuthException;
import org.gcube.data.access.storagehub.handlers.CredentialHandler;
import org.gcube.data.access.storagehub.handlers.DataHandler;
import org.gcube.data.access.storagehub.handlers.items.ItemHandler;
import org.gcube.data.access.storagehub.handlers.items.builders.FileCreationParameters;
import org.gcube.data.access.storagehub.handlers.items.builders.ItemsParameterBuilder;
import org.gcube.data.access.storagehub.repository.StoragehubRepository;
import org.gcube.data.access.storagehub.scripting.AbstractScript;
import org.gcube.data.access.storagehub.scripting.ScriptUtil;
import org.gcube.data.access.storagehub.services.RepositoryInitializer;
import org.gcube.data.access.storagehub.services.admin.ScriptStatus.Status;
import org.gcube.smartgears.ContextProvider;
import org.gcube.smartgears.context.application.ApplicationContext;
import org.gcube.smartgears.utils.InnerMethodName;
import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
import org.glassfish.jersey.media.multipart.FormDataParam;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.webcohesion.enunciate.metadata.rs.RequestHeader;
import com.webcohesion.enunciate.metadata.rs.RequestHeaders;
import jakarta.inject.Inject;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.DefaultValue;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.WebApplicationException;
import jakarta.ws.rs.core.MediaType;
@Path("admin/script")
@RequestHeaders({
@RequestHeader( name = "Authorization", description = "Bearer token, see https://dev.d4science.org/how-to-access-resources"),
})
public class ScriptManager {
private static Logger log = LoggerFactory.getLogger(ScriptManager.class);
private RepositoryInitializer repository = StorageHubAppllicationManager.repository;
private final StoragehubRepository repository = StoragehubRepository.repository;
@Inject
AccountingHandler accountingHandler;
@Context
ServletContext context;
@Inject
ScriptUtil scriptUtil;
@Inject
ItemHandler itemHandler;
@Inject
PathUtil pathUtil;
protected static HashMap<String, ScriptStatus> scriptStatusMap = new HashMap<String, ScriptStatus>();
@POST
@Path("execute")
@AuthorizationControl(allowedRoles = {INFRASTRUCTURE_MANAGER_ROLE},exception=MyAuthException.class)
@AuthorizationControl(allowedRoles = {INFRASTRUCTURE_MANAGER_ROLE})
@Consumes(MediaType.MULTIPART_FORM_DATA)
public String run( @FormDataParam("name") String name,
@FormDataParam("asynch") Boolean asynch,
@Produces(MediaType.APPLICATION_JSON)
public ScriptStatus run( @FormDataParam("name") String name,
@FormDataParam("asynch") @DefaultValue("false") Boolean asynch,
@FormDataParam("writeResult") @DefaultValue("false") Boolean writeResult ,
@FormDataParam("destinationFolderId") String destinationFolderId,
@FormDataParam("file") InputStream stream,
@FormDataParam("file") FormDataContentDisposition fileDetail) {
try {
InnerMethodName.set("executeScript");
ScriptClassLoader scriptClassLoader = new ScriptClassLoader(Thread.currentThread().getContextClassLoader());
Class<?> scriptClass = uploadClass(stream, scriptClassLoader, fileDetail.getFileName().replace(".class", ""));
return run(scriptClass, name, destinationFolderId, asynch!=null? asynch : false);
return internalRun(scriptClass, name, destinationFolderId, asynch, writeResult);
}catch(Throwable e) {
log.error("error executing script {}", name,e);
throw new WebApplicationException("error loading class",e);
}
}
@GET
@Path("{id}/status")
@AuthorizationControl(allowedRoles = {INFRASTRUCTURE_MANAGER_ROLE})
@Produces(MediaType.APPLICATION_JSON)
public ScriptStatus getStatus(@PathParam("id") String runningId) {
InnerMethodName.set("getScriptStatus");
if (!scriptStatusMap.containsKey(runningId)) {
log.error("script with id {} not found",runningId);
throw new WebApplicationException("id "+runningId+" not found", 404);
}
ScriptStatus status = scriptStatusMap.get(runningId);
if (status.getStatus()!= Status.Running)
scriptStatusMap.remove(runningId);
return status;
}
@POST
@Path("export")
@AuthorizationControl(allowedRoles = {INFRASTRUCTURE_MANAGER_ROLE})
@Consumes(MediaType.MULTIPART_FORM_DATA)
@Produces(MediaType.APPLICATION_JSON)
public ScriptStatus export() {
InnerMethodName.set("export");
try {
String runningId = UUID.randomUUID().toString();
ApplicationContext appContext = ContextProvider.get();
String serverHost = appContext.container().configuration().hostname();
final ScriptStatus status = new ScriptStatus(runningId, null, serverHost);
scriptStatusMap.put(runningId, status);
Runnable execution = () -> {
JackrabbitSession session = null;
try {
session = (JackrabbitSession) repository.getRepository().login();
DumpData dd = new DataHandler().exportData(session);
ObjectMapper om = new ObjectMapper();
status.setSuccess(om.writeValueAsString(dd));
log.info("""
export finished with result
---------------------------
{}
---------------------------
""", status.getResult());
} catch (Throwable t) {
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw, true);
t.printStackTrace(pw);
status.setFailed(sw.toString());
log.warn("export failed", t);
} finally {
if (session!=null)
session.logout();
}
};
new Thread(execution).start();
return status;
}catch(Exception e) {
throw new WebApplicationException("error starting export", e);
}
}
private Class<?> uploadClass(InputStream stream, ScriptClassLoader classLoader, String name) throws Throwable {
try(ByteArrayOutputStream buffer = new ByteArrayOutputStream()){
@ -97,33 +180,53 @@ public class ScriptManager {
}
private String run(Class<?> clazz, String name, String destinationFolderId, boolean asynch) throws Throwable {
String login = AuthorizationProvider.instance.get().getClient().getId();
private ScriptStatus internalRun(Class<?> clazz, String name, String destinationFolderId, boolean asynch, boolean writeResult) throws Throwable {
String login = SecretManagerProvider.get().getOwner().getId();
log.info("script {} called by {}", clazz.getSimpleName(), login);
JackrabbitSession ses = null;
try {
ses = (JackrabbitSession) repository.getRepository().login(CredentialHandler.getAdminCredentials(context));
String parentId = destinationFolderId!=null ? destinationFolderId : ses.getNode(pathUtil.getWorkspacePath(login).toPath()).getIdentifier();
Node parentNode = ses.getNodeByIdentifier(parentId);
String parentPath = parentNode.getPath();
String resultPath= null;
Node parentNode = null;
if (writeResult) {
JackrabbitSession ses = null;
try {
ses = (JackrabbitSession) repository.getRepository().login(Constants.JCR_CREDENTIALS);
String parentId = destinationFolderId!=null ? destinationFolderId : ses.getNode(pathUtil.getWorkspacePath(login).toPath()).getIdentifier();
parentNode = ses.getNodeByIdentifier(parentId);
resultPath = Paths.append(Paths.getPath(parentNode.getPath()), name).toPath();
}finally {
if (ses!=null)
ses.logout();
}
}
if (AbstractScript.class.isAssignableFrom(clazz)) {
AbstractScript scriptInstance = (AbstractScript) clazz.newInstance();
AbstractScript scriptInstance = (AbstractScript) clazz.getDeclaredConstructor().newInstance();
RealRun realRun = new RealRun(ses, scriptInstance, login, parentId, name);
if (asynch) {
ApplicationContext appContext = ContextProvider.get();
String serverHost = appContext.container().configuration().hostname();
String runningId = UUID.randomUUID().toString();
ScriptStatus status = new ScriptStatus(runningId, resultPath, serverHost);
RealRun realRun = new RealRun(scriptInstance, login, parentNode, name, writeResult, status);
if (asynch) {
scriptStatusMap.put(runningId, status);
new Thread(AuthorizedTasks.bind(realRun)).start();
}else realRun.run();
return status;
}else {
realRun.run();
return status;
}
} else throw new Exception("class "+clazz.getSimpleName()+" not implements AbstractScript");
return Paths.append(Paths.getPath(parentPath), name).toPath();
}catch (Throwable e) {
if (ses !=null && ses.isLive())
ses.logout();
throw e;
}
@ -133,51 +236,64 @@ public class ScriptManager {
class RealRun implements Runnable{
private JackrabbitSession ses;
AbstractScript instance;
String login;
String parentId;
Node parentNode;
String name;
boolean writeResult = true;
ScriptStatus status;
public RealRun(JackrabbitSession ses, AbstractScript instance, String login, String parentId, String name) {
public RealRun(AbstractScript instance, String login, Node parentNode, String name, boolean writeResult, ScriptStatus status) {
super();
this.ses = ses;
this.instance = instance;
this.login = login;
this.parentId = parentId;
this.parentNode = parentNode;
this.name = name;
this.writeResult = writeResult;
this.status = status;
}
@Override
public void run() {
try{
String result ="";
String result ="";
try {
JackrabbitSession executeSession = null;
try {
result = instance.run(ses, null, scriptUtil);
log.info("result is {}",result);
executeSession = (JackrabbitSession) repository.getRepository().login(Constants.JCR_CREDENTIALS);
result = instance.run(executeSession, null, scriptUtil);
status.setSuccess();
}catch(Throwable t) {
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw, true);
t.printStackTrace(pw);
status.setFailed(sw.toString());
result+= "\n"+sw.toString();
log.warn("error executing script {}",instance.getClass().getSimpleName(), t);
}finally {
if (executeSession !=null && executeSession.isLive())
executeSession.logout();
}
try( InputStream stream = new ReaderInputStream(new StringReader(result))){
ItemsParameterBuilder<FileCreationParameters> builder = FileCreationParameters.builder().name(name).description("result of script execution "+name)
.stream(stream).on(parentId).with(ses).author(login);
itemHandler.create(builder.build());
} catch (Throwable e) {
log.error("error saving script result {} in the Workspace",name, e);
if (this.writeResult) {
Session writeSession = null;
try( InputStream stream = new ByteArrayInputStream(result.getBytes())){
writeSession = repository.getRepository().login(Constants.JCR_CREDENTIALS);
ItemsParameterBuilder<FileCreationParameters> builder = FileCreationParameters.builder().name(name).description("result of script execution "+name)
.stream(stream).on(parentNode.getIdentifier()).with(writeSession).author(login);
itemHandler.create(builder.build());
} catch (Throwable e) {
log.error("error saving script result {} in the Workspace",name, e);
} finally {
if (writeSession!=null)
writeSession.logout();
}
}
} finally {
if (ses!=null)
ses.logout();
}catch (Exception e) {
log.error("unexpected error executing script {}",instance.getClass().getSimpleName(),e);
}
}
}
class ScriptClassLoader extends ClassLoader{
@ -192,3 +308,6 @@ public class ScriptManager {
}
}

View File

@ -0,0 +1,108 @@
package org.gcube.data.access.storagehub.services.admin;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
public class ScriptStatus {
enum Status {
Running, Success, Failed
}
private static final DateFormat dateFormat = new SimpleDateFormat("dd MMM yyyy HH:mm:ss:SSS Z") ;
private Status status;
private String errorMessage;
private String result;
private long start;
private long finished = -1;
private String runningId;
private String executionServer;
public ScriptStatus(String runningId, String resultPath, String executionServer) {
super();
this.status = Status.Running;
this.start = System.currentTimeMillis();
this.runningId = runningId;
this.result = resultPath;
this.executionServer = executionServer;
}
public ScriptStatus(String runningId, String executionServer) {
super();
this.status = Status.Running;
this.start = System.currentTimeMillis();
this.runningId = runningId;
this.executionServer = executionServer;
}
public void setFailed(String error) {
this.status = Status.Failed;
this.errorMessage = error;
this.finished = System.currentTimeMillis();
}
public void setSuccess() {
this.status = Status.Success;
this.finished = System.currentTimeMillis();
}
public void setSuccess(String result) {
this.status = Status.Success;
this.finished = System.currentTimeMillis();
this.result = result;
}
public Status getStatus() {
return status;
}
public String getErrorMessage() {
return errorMessage;
}
public String getStartDate() {
Date date = new Date(this.start);
return dateFormat.format(date);
}
public long getDurationInMillis() {
long toUse = finished;
if (finished < 0)
toUse = System.currentTimeMillis();
return toUse-start;
}
public String getHumanReadableDuration() {
long toUse = finished;
if (finished < 0)
toUse = System.currentTimeMillis();
long duration = toUse - this.start;
long minutes = (duration/1000)/60;
long seconds = (duration/1000)%60;
return String.format("%d minutes %d seconds", minutes, seconds);
}
public String getResult() {
return result;
}
public String getRunningId() {
return runningId;
}
public String getExecutionServer() {
return executionServer;
}
}

Some files were not shown because too many files have changed in this diff Show More