Compare commits

..

No commits in common. "feature/28427" and "master" have entirely different histories.

25 changed files with 208 additions and 1499 deletions

View File

@ -1,3 +1,3 @@
FROM harbor.d4science.org/gcube/smartgears-distribution:4.0.1-SNAPSHOT-java17-tomcat10.1.19
FROM d4science/smartgears-distribution:4.0.1-SNAPSHOT-java17-tomcat10.1.19
COPY ./target/storagehub.war /tomcat/webapps/
COPY ./docker/storagehub.xml /tomcat/conf/Catalina/localhost/

View File

@ -1,4 +1,4 @@
FROM harbor.d4science.org/gcube/smartgears-distribution:4.0.0-SNAPSHOT-java17-tomcat10.1.19
FROM d4science/smartgears-distribution:4.0.0-SNAPSHOT-java17-tomcat10.1.19
#install unzip
RUN apt-get update && apt-get install unzip

View File

@ -1,9 +1,8 @@
FROM harbor.d4science.org/gcube/smartgears-distribution:4.0.0-SNAPSHOT-java17-tomcat10.1.19
FROM smartgears-distribution:4.0.0-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
RUN apt update && apt install -y vim
COPY ./docker/storage-settings.properties /etc/config/storagehub/

View File

@ -1,3 +1,4 @@
version: '3.7'
services:
elb:
image: haproxy

View File

@ -1,3 +1,4 @@
version: '3.7'
services:
postgres:
image: postgres:16.2

View File

@ -1,3 +1,4 @@
version: '3.7'
services:
storagehub:
image: d4science/storagehub:latest

View File

@ -1,31 +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>
<appender name="FILE" class="ch.qos.logback.core.FileAppender">
<file>storagehub.log</file>
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
<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.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" />
<logger name="org.gcube.data.access.storagehub.handlers" level="DEBUG"/>
<root level="WARN">
<appender-ref ref="STDOUT" />
<appender-ref ref="FILE" />
</root>
<appender-ref ref="STDOUT" />
</root>
</configuration>

View File

@ -1,20 +0,0 @@
# Minimal makefile for Sphinx documentation
#
# You can set these variables from the command line, and also
# from the environment for the first two.
SPHINXOPTS ?=
SPHINXBUILD ?= sphinx-build
SOURCEDIR = .
BUILDDIR = _build
# Put it first so that "make" without argument is like "make help".
help:
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
.PHONY: help Makefile
# Catch-all target: route all unknown targets to Sphinx using the new
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
%: Makefile
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)

View File

@ -1,58 +0,0 @@
# Configuration file for the Sphinx documentation builder.
#
# This file only contains a selection of the most common options. For a full
# list see the documentation:
# https://www.sphinx-doc.org/en/master/usage/configuration.html
# -- Path setup --------------------------------------------------------------
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
#
# import os
# import sys
# sys.path.insert(0, os.path.abspath('.'))
# -- Project information -----------------------------------------------------
project = 'StorageHub'
copyright = '2024, Lucio Lelii, Biagio Peccerillo'
author = 'Lucio Lelii, Biagio Peccerillo'
# The full version, including alpha/beta/rc tags
release = '2.0.1'
# -- General configuration ---------------------------------------------------
source_suffix = {
'.rst': 'restructuredtext',
}
# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = []
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
# This pattern also affects html_static_path and html_extra_path.
exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
# -- Options for HTML output -------------------------------------------------
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
#
html_theme = 'sphinx_rtd_theme'
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static']

View File

@ -1,8 +0,0 @@
Welcome to StorageHub's documentation!
======================================
.. toctree::
:maxdepth: 2
:caption: Contents:
intro.rst

View File

@ -1,98 +0,0 @@
Introduction
============
StorageHub is a versatile service designed to provide seamless access
to various storage resources, ensuring data persistence and management. It acts
as an intermediary layer that can interface with any underlying storage
solution, such as Amazon S3 or MongoDB, offering a unified and flexible approach
to storage management.
Base URL
--------
In the production environment, its current value is https://api.d4science.org/
Key Features
------------
Flexibility and Integration
~~~~~~~~~~~~~~~~~~~~~~~~~~~
StorageHub is designed to be highly flexible, allowing it to serve as an
intermediate layer for diverse storage solutions. This flexibility ensures that
it can adapt to different storage backends without requiring significant changes
to the applications that rely on it.
RESTful Interface
~~~~~~~~~~~~~~~~~
StorageHub exposes a RESTful API, which allows any application capable of making
HTTP requests to access it. This REST interface provides a standardized way to
interact with the storage resources, enabling easy integration with various
applications and services. See the available REST-API on `StorageHub API docs
<../api-docs/index.html>`_.
Metadata Management
~~~~~~~~~~~~~~~~~~~
StorageHub leverages a JackRabbit-based object store to manage all metadata
associated with the stored data. This ensures that metadata is efficiently
organized and easily retrievable, enhancing the overall data management
capabilities of the service.
Direct Payload Storage
~~~~~~~~~~~~~~~~~~~~~~
While metadata is handled by JackRabbit, the actual data payloads are stored
directly on the underlying storage solutions. This approach optimizes storage
efficiency and performance, ensuring that large data payloads are managed
effectively.
Primary Use Cases
-----------------
Workspace
~~~~~~~~~
The main application that interacts with StorageHub is the Workspace portlet,
which is easily accessible from the Virtual Research Environments (VREs). The
Workspace provides a "standard" HTML interface where users can perform all the
common operations available in a file system, such as creating, reading,
updating, and deleting files and directories.
In addition to these standard file system operations, the Workspace offers
features that are specific to VREs. These include publishing on the Catalogue,
sharing resources with other users, and managing versions of files. These
capabilities make the Workspace a versatile tool for managing data within the
VREs, leveraging the services provided by StorageHub.
Java Client
~~~~~~~~~~~
The methods of the Web Service can be called by writing your own REST client
application or by using already existing REST client plugins.
In case of a Java client, we provide the StorageHub Client Library, which is a
Java library designed to facilitate seamless interaction with StorageHub. It
abstracts the complexities of the REST API, providing a more intuitive and
convenient interface for Java developers.
The StorageHub Client Library allows developers to easily integrate StorageHub's
capabilities into their applications without dealing with the intricacies of
HTTP requests and responses. The library handles all the necessary communication
with StorageHub, allowing developers to focus on their application's core
functionality.
.. tip:: If you're coding in Java, it is recommended that you include the
StorageHub Client Library into your project.
Authorization
-------------
D4Science adopts state-of-the-art industry standards for authentication and
authorization. Specifically, the implementation fully adopts `OIDC (OpenID
Connect) <https://openid.net/connect>`_ for authentication and UMA 2 (User
Managed Authorization) for authorization flows. `JSON Web Token (JWT) Access
token <https://jwt.io/>`_ are used for both authentication and authorization.
Obtain your Bearer token here: https://dev.d4science.org/how-to-access-resources

View File

@ -1,35 +0,0 @@
@ECHO OFF
pushd %~dp0
REM Command file for Sphinx documentation
if "%SPHINXBUILD%" == "" (
set SPHINXBUILD=sphinx-build
)
set SOURCEDIR=.
set BUILDDIR=_build
if "%1" == "" goto help
%SPHINXBUILD% >NUL 2>NUL
if errorlevel 9009 (
echo.
echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
echo.installed, then set the SPHINXBUILD environment variable to point
echo.to the full path of the 'sphinx-build' executable. Alternatively you
echo.may add the Sphinx directory to PATH.
echo.
echo.If you don't have Sphinx installed, grab it from
echo.https://www.sphinx-doc.org/
exit /b 1
)
%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
goto end
:help
%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
:end
popd

View File

@ -1,41 +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.18.0.xsd">
<description>
<![CDATA[
<h1>StorageHUB</h1>
<p>StorageHUB is the service implementing the gCube Workspace feature.</p>
<p>It provides an intermediate layer between the storage and the services
willing to access it.</p>
]]>
</description>
<code-license>This project is licensed under the EUPL V.1.1 License - see the LICENSE.md file for details.</code-license>
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" />
<java-xml-client disabled="true" />
<jaxb disabled="true" />
<jaxws disabled="true" />
<c-xml-client disabled="true" />
<csharp-xml-client disabled="true" />
<obj-c-xml-client disabled="true" />
<php-xml-client disabled="true" />
<spring-webnt disabled="true" />
<jaxrs groupBy="class" disableExamples="false" path-sort-strategy="depth_first" />
<swagger basePath="/workspace" />
<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" />
<additional-css
file="css/d4science_enunciate_custom.css" />
</docs>
<swagger basePath="/workspace" />
</modules>
</enunciate>

54
pom.xml
View File

@ -10,7 +10,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>org.gcube.data.access</groupId>
<artifactId>storagehub</artifactId>
<version>2.0.1-SNAPSHOT</version>
<version>2.0.0</version>
<name>storagehub</name>
<scm>
<connection>
@ -32,7 +32,7 @@
<warname>storagehub</warname>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<enunciate.version>2.18.1</enunciate.version>
<enunciate.version>2.17.1</enunciate.version>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<java_version>17</java_version>
@ -42,7 +42,7 @@
<dependency>
<groupId>org.gcube.distribution</groupId>
<artifactId>gcube-smartgears-bom</artifactId>
<version>4.0.1-SNAPSHOT</version>
<version>4.0.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
@ -428,32 +428,7 @@
<groupId>com.webcohesion.enunciate</groupId>
<artifactId>enunciate-maven-plugin</artifactId>
<version>${enunciate.version}</version>
<dependencies>
<dependency>
<groupId>com.webcohesion.enunciate</groupId>
<artifactId>enunciate-lombok</artifactId>
<version>2.9.1</version>
</dependency>
</dependencies>
<configuration>
<sourcepath-includes>
<!-- Include storagehub classes -->
<sourcepath-include>
<groupId>org.gcube.common</groupId>
<artifactId>storagehub</artifactId>
</sourcepath-include>
<!-- Include storagehub-model classes -->
<sourcepath-include>
<groupId>org.gcube.common</groupId>
<artifactId>storagehub-model</artifactId>
</sourcepath-include>
<!-- Include jersey media classes -->
<sourcepath-include>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-multipart</artifactId>
</sourcepath-include>
</sourcepath-includes>
</configuration>
<configuration></configuration>
<executions>
<execution>
<id>assemble</id>
@ -490,27 +465,6 @@
</execution>
</executions>
</plugin>
<!-- SPHINX PLUGIN triggered at 'compile' -->
<plugin>
<groupId>kr.motd.maven</groupId>
<artifactId>sphinx-maven-plugin</artifactId>
<version>2.10.0</version>
<configuration>
<outputDirectory>
${project.build.directory}/${project.artifactId}/docs</outputDirectory>
<builder>html</builder>
<configDirectory>${basedir}/docs</configDirectory>
<sourceDirectory>${basedir}/docs</sourceDirectory>
</configuration>
<executions>
<execution>
<phase>process-resources</phase>
<goals>
<goal>generate</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
<profiles>

View File

@ -35,19 +35,14 @@ import org.glassfish.jersey.media.multipart.FormDataParam;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.webcohesion.enunciate.metadata.DocumentationExample;
import com.webcohesion.enunciate.metadata.rs.RequestHeader;
import com.webcohesion.enunciate.metadata.rs.RequestHeaders;
import com.webcohesion.enunciate.metadata.rs.ResourceMethodSignature;
import com.webcohesion.enunciate.metadata.rs.ResponseCode;
import com.webcohesion.enunciate.metadata.rs.StatusCodes;
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;
@ -58,13 +53,10 @@ import jakarta.ws.rs.core.Context;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
/**
* Manage the Access Control List of shared folders
*/
@Path("items")
@ManagedBy(StorageHubApplicationManager.class)
@RequestHeaders({
@RequestHeader( name = "Authorization", description = "Bearer token, see <a href=\"https://dev.d4science.org/how-to-access-resources\">https://dev.d4science.org/how-to-access-resources</a>"),
@RequestHeader( name = "Authorization", description = "Bearer token, see https://dev.d4science.org/how-to-access-resources"),
})
public class ACLManager extends Impersonable {
@ -99,13 +91,9 @@ public class ACLManager extends Impersonable {
/**
* returns the AccessType for all the users in a shared folder
*
* @param id id of the shared folder
* @exception {@link RepositoryException} when a generic jcr error occurs
* @exception {@link UserNotAuthorizedException} when the caller is not authorized to access to the shared folder
*/
@ResourceMethodSignature(output = ACLList.class, pathParams = { @PathParam("id") })
@StatusCodes({
@ResponseCode ( code = 200, condition = "Shared folder found."),
@ResponseCode ( code = 500, condition = "This item does not exist."),
})
@GET
@Path("{id}/acls")
@Produces(MediaType.APPLICATION_JSON)
@ -134,26 +122,15 @@ public class ACLManager extends Impersonable {
/**
* Set a new AccessType for a user in a shared folder or VRE folder
*
* @param id id of the shared folder
* @param user user id
* @param access access type<br>
* <strong>Possible values:</strong> <code>READ_ONLY</code>, <code>WRITE_OWNER</code>, <code>WRITE_ALL</code>, <code>ADMINISTRATOR</code>
*
* @param String user
* @param accessType accessType
*
* @exception {@link RepositoryException} when a generic jcr error occurs
* @exception {@link UserNotAuthorizedException} when the caller is not ADMINISTRATOR of the shared folder
* @exception {@link InvalidCallParameters} when the folder is not shared with the specified user
* @exception {@link InvalidItemException} when the folder is not share
*/
@ResourceMethodSignature(output = void.class, pathParams = { @PathParam("id") }, formParams = {
@FormParam("user"), @FormParam("access") })
@StatusCodes({
@ResponseCode ( code = 204, condition = "Access type updated."),
@ResponseCode ( code = 400, condition = "User does not exist."),
@ResponseCode ( code = 415, condition = "Wrong content type."),
@ResponseCode ( code = 500, condition = "This shared item does not exist or wrong access type."),
})
@DocumentationExample(value = "...\n\n--------boundaryString\n" +
"Content-Disposition: form-data; name=\"user\"\n\n" +
"user2\n" +
"--------boundaryString\n" +
"Content-Disposition: form-data; name=\"accessType\"\n\n" +
"WRITE_OWNER\n" +
"--------boundaryString--")
@PUT
@Consumes(MediaType.MULTIPART_FORM_DATA)
@Path("{id}/acls")
@ -209,17 +186,18 @@ public class ACLManager extends Impersonable {
}
/**
* Remove a user from the shared folder
* remove right for a user only on Shared folder
*
* @param id id of the shared folder
* @param user user id
*
* @param String user
*
*
* @exception {@link RepositoryException} when a generic jcr error occurs
* @exception {@link UserNotAuthorizedException} when the caller is not ADMINISTRATOR of the shared folder
* @exception {@link InvalidCallParameters} when the folder is not shared with the specified user
* @exception {@link InvalidItemException} when the folder is not share
*/
@ResourceMethodSignature(output = void.class, pathParams = { @PathParam("id"), @PathParam("user") })
@StatusCodes({
@ResponseCode ( code = 204, condition = "User removed."),
@ResponseCode ( code = 415, condition = "Wrong content type."),
@ResponseCode ( code = 500, condition = "This shared item does not exist."),
})
//TODO: is this method correct? can ACL be removed, is correct that this means an unshare operation?
@DELETE
@Consumes(MediaType.TEXT_PLAIN)
@Path("{id}/acls/{user}")
@ -255,20 +233,7 @@ public class ACLManager extends Impersonable {
}
}
/**
* Check if the current user can write on the shared folder
*
* @param id id of the shared folder
* @return true if the current user can write on the shared folder, false otherwise
* @responseExample text/plain true
*/
@ResourceMethodSignature(output = Boolean.class, pathParams = { @PathParam("id") })
@StatusCodes({
@ResponseCode ( code = 200, condition = "Shared folder found."),
@ResponseCode ( code = 406, condition = "This shared folder does not exist."),
})
@GET
@Produces(MediaType.TEXT_PLAIN)
@Path("{id}/acls/write")
public Boolean canWriteInto() {
InnerMethodName.set("canWriteIntoFolder");

View File

@ -14,14 +14,11 @@ import jakarta.ws.rs.core.Response.Status;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.webcohesion.enunciate.metadata.Ignore;
@Path("api-docs")
public class DocsGenerator {
private static Logger logger = LoggerFactory.getLogger(DocsGenerator.class);
@Ignore
@GET
@Path("/{any: .*}")
public InputStream toDoc(@Context HttpServletRequest req) throws WebApplicationException {

View File

@ -28,12 +28,8 @@ import org.glassfish.jersey.media.multipart.FormDataParam;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.webcohesion.enunciate.metadata.DocumentationExample;
import com.webcohesion.enunciate.metadata.rs.RequestHeader;
import com.webcohesion.enunciate.metadata.rs.RequestHeaders;
import com.webcohesion.enunciate.metadata.rs.ResourceMethodSignature;
import com.webcohesion.enunciate.metadata.rs.ResponseCode;
import com.webcohesion.enunciate.metadata.rs.StatusCodes;
import jakarta.inject.Inject;
import jakarta.inject.Singleton;
@ -50,14 +46,11 @@ import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
/**
* Manages groups
*/
@Path("groups")
@Singleton
@ManagedBy(StorageHubApplicationManager.class)
@RequestHeaders({
@RequestHeader( name = "Authorization", description = "Bearer token, see <a href=\"https://dev.d4science.org/how-to-access-resources\">https://dev.d4science.org/how-to-access-resources</a>"),
@RequestHeader( name = "Authorization", description = "Bearer token, see https://dev.d4science.org/how-to-access-resources"),
})
public class GroupManager {
@ -73,15 +66,6 @@ public class GroupManager {
PathUtil pathUtil;
/**
* Get list of the groups for the current user
*
* @return list of groups
* @responseExample text/plain ["group1", "group2", "group3"]
*/
@StatusCodes({
@ResponseCode ( code = 200, condition = "Success."),
})
@GET
@Path("")
@Produces(MediaType.APPLICATION_JSON)
@ -103,44 +87,9 @@ public class GroupManager {
return groups;
}
/**
* Create a new group <br>
* <strong>Only users with <code>Infrastructure-Manager</code> role allowed</strong>
*
* @param group group name
* @param accessType access type<br> <strong>Possible values:</strong> <code>READ_ONLY</code>, <code>WRITE_OWNER</code>, <code>WRITE_ALL</code>, <code>ADMINISTRATOR</code>
* @param folderOwner folder owner
* @param useDefaultStorage use default storage if true<br>
* <strong>Possible values:</strong> <code>true</code>, <code>false</code><br>
* <strong>Optional</strong> default: <code>true</code>
* @return group name
* @responseExample text/plain "group"
*/
@ResourceMethodSignature(output = String.class, formParams = {
@FormParam("group"), @FormParam("accessType"), @FormParam("folderOwner"), @FormParam("useDefaultStorage") })
@StatusCodes({
@ResponseCode ( code = 200, condition = "Success."),
@ResponseCode ( code = 403, condition = "You're not allowed to create groups."),
@ResponseCode ( code = 406, condition = "Error creating group."),
@ResponseCode ( code = 415, condition = "Wrong content type."),
})
@DocumentationExample(value = "...\n\n--------boundaryString\n" +
"Content-Disposition: form-data; name=\"group\"\n\n" +
"my_group\n" +
"--------boundaryString\n" +
"Content-Disposition: form-data; name=\"accessType\"\n\n" +
"ADMINISTRATOR\n" +
"--------boundaryString\n" +
"Content-Disposition: form-data; name=\"folderOwner\"\n\n" +
"user1\n" +
"--------boundaryString\n" +
"Content-Disposition: form-data; name=\"useDefaultStorage\"\n\n" +
"true\n" +
"--------boundaryString--")
@POST
@Path("")
@Consumes(MediaType.MULTIPART_FORM_DATA)
@Produces(MediaType.TEXT_PLAIN)
@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){
@ -163,22 +112,8 @@ public class GroupManager {
return group;
}
/**
* Delete a group <br>
* <strong>Only users with <code>Infrastructure-Manager</code> role allowed</strong>
*
* @param group group name
* @return group name
* @responseExample text/plain "group"
*/
@StatusCodes({
@ResponseCode ( code = 200, condition = "Success."),
@ResponseCode ( code = 403, condition = "You're not allowed to delete groups."),
@ResponseCode ( code = 406, condition = "Error deleting group."),
})
@DELETE
@Path("{group}")
@Produces(MediaType.TEXT_PLAIN)
@AuthorizationControl(allowedRoles={INFRASTRUCTURE_MANAGER_ROLE})
public String deleteGroup(@PathParam("group") String group){
@ -203,18 +138,6 @@ public class GroupManager {
public boolean isVREManager() { return SecretManagerProvider.get().getOwner().getRoles().contains(VREMANAGER_ROLE); }
/**
* Add an administrator to a group
*
* @param id group name
* @param userId user name
*/
@StatusCodes({
@ResponseCode ( code = 204, condition = "Success."),
@ResponseCode ( code = 406, condition = "Error adding an admin."),
@ResponseCode ( code = 415, condition = "Wrong content type."),
})
@ResourceMethodSignature(output = String.class, pathParams = { @PathParam("id")}, formParams = { @FormParam("userId") })
@PUT
@Path("{id}/admins")
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
@ -252,20 +175,9 @@ public class GroupManager {
}
/**
* Remove an administrator from a group. The removed admin remains in the group as a <em>normal</em> user.
*
* @param id group name
* @param userId user name
*/
@StatusCodes({
@ResponseCode ( code = 204, condition = "Success."),
@ResponseCode ( code = 406, condition = "Error removing an admin."),
@ResponseCode ( code = 415, condition = "Wrong content type."),
})
@ResourceMethodSignature(output = void.class, pathParams = { @PathParam("id")}, formParams = { @FormParam("userId") })
@DELETE
@Path("{id}/admins/{userId}")
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
public void removeAdmin(@PathParam("id") String groupId, @PathParam("userId") String userId){
InnerMethodName.set("removeAdmin");
@ -298,16 +210,6 @@ public class GroupManager {
}
}
/**
* Get the list of administrators of a group
*
* @param groupId group name
* @return list of administrators
*/
@StatusCodes({
@ResponseCode ( code = 200, condition = "Success."),
@ResponseCode ( code = 406, condition = "This group does not exist."),
})
@GET
@Path("{groupId}/admins")
@Produces(MediaType.APPLICATION_JSON)
@ -334,23 +236,6 @@ public class GroupManager {
}
/**
* Add a user to a group <br>
* <strong>Only users with <code>Infrastructure-Manager</code> or <code>VRE-Manager</code> role allowed</strong>
*
* @param id group name
* @param userId user name
* @return true if the user has been added to the group
* @responseExample text/plain true
*/
@StatusCodes({
@ResponseCode ( code = 200, condition = "Success."),
@ResponseCode ( code = 403, condition = "You're not allowed to add users to groups."),
@ResponseCode ( code = 406, condition = "Group or user does not exist."),
@ResponseCode ( code = 415, condition = "Wrong content type."),
})
@ResourceMethodSignature(output = boolean.class, pathParams = { @PathParam("id")}, formParams = { @FormParam("userId") })
@DocumentationExample(value = "...\n\nuserId=user1\n")
@PUT
@Path("{id}/users")
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
@ -386,19 +271,6 @@ public class GroupManager {
/**
* Remove a user from a group <br>
* <strong>Only users with <code>Infrastructure-Manager</code> or <code>VRE-Manager</code> role allowed</strong>
*
* @param groupId group name
* @param userId user name
* @return true if the user has been removed from the group
*/
@StatusCodes({
@ResponseCode ( code = 200, condition = "Success."),
@ResponseCode ( code = 403, condition = "You're not allowed to add users to groups."),
@ResponseCode ( code = 406, condition = "Group or user does not exist."),
})
@DELETE
@Path("{groupId}/users/{userId}")
@AuthorizationControl(allowedRoles={VREMANAGER_ROLE, INFRASTRUCTURE_MANAGER_ROLE})
@ -432,17 +304,6 @@ public class GroupManager {
return success;
}
/**
* Get the list of users of a group <br>
* <strong>Only users with <code>Infrastructure-Manager</code> or <code>VRE-Manager</code> role allowed</strong>
*
* @param groupId group name
* @return list of users
*/
@StatusCodes({
@ResponseCode ( code = 200, condition = "Success."),
@ResponseCode ( code = 406, condition = "Group does not exist."),
})
@GET
@Path("{groupId}/users")
@Produces(MediaType.APPLICATION_JSON)

View File

@ -42,17 +42,13 @@ import org.glassfish.jersey.media.multipart.FormDataParam;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.webcohesion.enunciate.metadata.DocumentationExample;
import com.webcohesion.enunciate.metadata.Ignore;
import com.webcohesion.enunciate.metadata.rs.RequestHeader;
import com.webcohesion.enunciate.metadata.rs.RequestHeaders;
import com.webcohesion.enunciate.metadata.rs.ResourceMethodSignature;
import jakarta.enterprise.context.RequestScoped;
import jakarta.inject.Inject;
import jakarta.servlet.ServletContext;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.FormParam;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.PUT;
@ -63,12 +59,10 @@ import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
/**
* Manage item sharing.
*/
@Path("items")
@RequestHeaders({
@RequestHeader( name = "Authorization", description = "Bearer token, see <a href=\"https://dev.d4science.org/how-to-access-resources\">https://dev.d4science.org/how-to-access-resources</a>"),
@RequestHeader( name = "Authorization", description = "Bearer token, see https://dev.d4science.org/how-to-access-resources"),
})
public class ItemSharing extends Impersonable{
@ -98,12 +92,10 @@ public class ItemSharing extends Impersonable{
@Inject Node2ItemConverter node2Item;
@Inject Item2NodeConverter item2Node;
// TODO: Remove this method - not used by anyone
@Ignore
@POST
@SuppressWarnings("unchecked")
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
@Produces(MediaType.TEXT_PLAIN)
@POST
@Path("{id}/share")
public String shareWithMap(@FormParam("mapUserPermission") String mapUserPermissionString, @FormParam("defaultAccessType") String defaultAccessTypeString){
InnerMethodName.set("shareFolder");
@ -205,32 +197,9 @@ public class ItemSharing extends Impersonable{
/**
* Share an item with some users and set its access type.
*
* @param id id of the item
* @param users set of users
* @param defaultAccessType default access type<br>
* <strong>Possible values:</strong> <code>READ_ONLY</code>, <code>WRITE_OWNER</code>, <code>WRITE_ALL</code>, <code>ADMINISTRATOR</code>
* @return id of the shared item
* @responseExample text/plain 5f4b3b4e-4b3b- ... -4b3b4e4b3b4e
*/
@ResourceMethodSignature(output = String.class, pathParams = { @PathParam("id") }, formParams = {
@FormParam("users"), @FormParam("defaultAccessType") })
@DocumentationExample("...\n\n--------boundaryString\n" +
"Content-Disposition: form-data; name=\"users\"\n\n" +
"user1\n" +
"--------boundaryString\n" +
"Content-Disposition: form-data; name=\"users\"\n\n" +
"user2\n" +
"--------boundaryString\n" +
"Content-Disposition: form-data; name=\"defaultAccessType\"\n\n" +
"READ_ONLY\n" +
"------boundaryString--")
@PUT
@Path("{id}/share")
@Consumes(MediaType.MULTIPART_FORM_DATA)
@Produces(MediaType.TEXT_PLAIN)
public String share(@FormDataParam("users") Set<String> users, @FormDataParam("defaultAccessType") AccessType accessType){
InnerMethodName.set("shareFolder");
Session ses = null;
@ -370,24 +339,9 @@ public class ItemSharing extends Impersonable{
}
/**
* Unshare an item with some users.
*
* @param id id of the item
* @param users set of users
* @return id of the unshared item
* @responseExample text/plain 5f4b3b4e-4b3b- ... -4b3b4e4b3b4e
*/
@ResourceMethodSignature(output = String.class, pathParams = { @PathParam("id") }, formParams = {
@FormParam("users") })
@DocumentationExample("...\n\n--------boundaryString\n" +
"Content-Disposition: form-data; name=\"users\"\n\n" +
"user1,user2,user3\n" +
"--------boundaryString--")
@PUT
@Path("{id}/unshare")
@Consumes(MediaType.MULTIPART_FORM_DATA)
@Produces(MediaType.TEXT_PLAIN)
public String unshare(@FormDataParam("users") Set<String> users){
InnerMethodName.set("unshareFolder");
Session ses = null;

View File

@ -39,13 +39,8 @@ import org.glassfish.jersey.media.multipart.FormDataParam;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.webcohesion.enunciate.metadata.DocumentationExample;
import com.webcohesion.enunciate.metadata.Ignore;
import com.webcohesion.enunciate.metadata.rs.RequestHeader;
import com.webcohesion.enunciate.metadata.rs.RequestHeaders;
import com.webcohesion.enunciate.metadata.rs.ResourceMethodSignature;
import com.webcohesion.enunciate.metadata.rs.ResponseCode;
import com.webcohesion.enunciate.metadata.rs.StatusCodes;
import jakarta.inject.Inject;
import jakarta.servlet.ServletContext;
@ -55,20 +50,17 @@ import jakarta.ws.rs.FormParam;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.Context;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
/**
* Manage item creation.
*/
@Path("items")
@ManagedBy(StorageHubApplicationManager.class)
@RequestHeaders({
@RequestHeader(name = "Authorization", description = "Bearer token, see <a href=\"https://dev.d4science.org/how-to-access-resources\">https://dev.d4science.org/how-to-access-resources</a>")
})
public class ItemsCreator extends Impersonable {
@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);
@ -80,29 +72,8 @@ public class ItemsCreator extends Impersonable {
@Inject
ItemHandler itemHandler;
/**
* Create a folder.
*
* @param id destination parent folder id
* @param name destination folder name
* @param description description meta-info for the created folder
* @param hidden hidden folder if true<br>
* <strong>Possible values:</strong> <code>true</code>, <code>false</code> <br>
* <strong>Optional</strong> default: <code>false</code>
* @return id of the created folder
* @responseExample text/plain 5f4b3b4e-4b3b- ... -4b3b4e4b3b4e
*/
@ResourceMethodSignature(output = String.class, pathParams = { @PathParam("id") }, formParams = {
@FormParam("name"), @FormParam("description"), @FormParam("hidden") })
@DocumentationExample(" ...\n\nname=sampleFolder&description=This+is+a+sample+folder&hidden=false")
@POST
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
@Produces(MediaType.TEXT_PLAIN)
@StatusCodes({
@ResponseCode ( code = 200, condition = "Folder created."),
@ResponseCode ( code = 400, condition = "Wrong set of parameters."),
@ResponseCode ( code = 415, condition = "Wrong content type."),
})
@Path("/{id}/create/FOLDER")
public Response createFolder(@PathParam("id") String id, @FormParam("name") String name,
@FormParam("description") String description, @FormParam("hidden") boolean hidden) {
@ -110,31 +81,29 @@ public class ItemsCreator extends Impersonable {
log.info("create folder item called");
Session ses = null;
String toReturn = null;
try {
try{
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) {
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 ){
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));
} catch (Throwable e) {
}catch(Throwable e ){
log.error("unexpected error", e);
GXOutboundErrorResponse.throwException(new BackendGenericError(e));
} finally {
if (ses != null)
}finally{
if (ses!=null)
ses.logout();
}
return Response.ok(toReturn).build();
}
@Ignore
@POST
@AuthorizationControl(allowedRoles = { INFRASTRUCTURE_MANAGER_ROLE })
@AuthorizationControl(allowedRoles={INFRASTRUCTURE_MANAGER_ROLE})
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
@Path("/{id}/create/EXTERNALFOLDER")
public Response createExternalFolder(@PathParam("id") String id, @FormParam("name") String name,
@ -145,7 +114,7 @@ public class ItemsCreator extends Impersonable {
log.info("create folder item called");
Session ses = null;
String toReturn = null;
try {
try{
Iterator<String> paramIt = request.getParameterNames().asIterator();
Iterable<String> iterable = () -> paramIt;
Stream<String> targetStream = StreamSupport.stream(iterable.spliterator(), false);
@ -155,81 +124,60 @@ public class ItemsCreator extends Impersonable {
targetStream.filter(v -> v.startsWith("plugin."))
.forEach(v -> pluginParams.add(v.replace("plugin.", ""), request.getParameter(v)));
log.debug("parameters for external folder with plugin {} are {}", pluginName, pluginParams.toString());
log.debug("parameters for external folder with plugin {} are {}",pluginName, pluginParams.toString());
ses = repository.getRepository().login(Constants.JCR_CREDENTIALS);
ItemsParameterBuilder<FolderCreationParameters> builder = FolderCreationParameters.builder().name(name)
.description(description).onRepository(pluginName).withParameters(pluginParams.getParameters())
.hidden(hidden).on(id).with(ses).author(currentUser);
toReturn = itemHandler.create(builder.build());
} catch (StorageHubException she) {
.description(description).onRepository(pluginName).withParameters(pluginParams.getParameters()).hidden(hidden).on(id).with(ses).author(currentUser);
toReturn = itemHandler.create(builder.build());
}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));
} catch (Throwable e) {
}catch(Throwable e ){
log.error("unexpected error", e);
GXOutboundErrorResponse.throwException(new BackendGenericError(e));
} finally {
if (ses != null)
}finally{
if (ses!=null)
ses.logout();
}
return Response.ok(toReturn).build();
}
/**
* Create a URL.
*
* @param id destination parent folder id
* @param name destination URL name
* @param description description meta-info for the created URL
* @param value URL address
* @return id of the created URL
* @responseExample text/plain 5f4b3b4e-4b3b- ... -4b3b4e4b3b4e
*/
@DocumentationExample(" ...\n\nname=d4science&description=D4Science+URL&value=www.d4science.org")
@POST
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
@Produces(MediaType.TEXT_PLAIN)
@StatusCodes({
@ResponseCode ( code = 200, condition = "URL created."),
@ResponseCode ( code = 400, condition = "Wrong set of parameters."),
@ResponseCode ( code = 406, condition = "Unable to create URL."),
@ResponseCode ( code = 415, condition = "Wrong content type."),
})
@Path("/{id}/create/URL")
public Response createURL(@PathParam("id") String id, @FormParam("name") String name,
@FormParam("description") String description, @FormParam("value") URL value) {
public Response createURL(@PathParam("id") String id, @FormParam("name") String name, @FormParam("description") String description, @FormParam("value") URL value) {
InnerMethodName.set("createItem(URL)");
log.info("create url called");
Session ses = null;
String toReturn = null;
try {
try{
ses = repository.getRepository().login(Constants.JCR_CREDENTIALS);
ItemsParameterBuilder<URLCreationParameters> builder = URLCreationParameters.builder().name(name)
.description(description).url(value).on(id).with(ses).author(currentUser);
ItemsParameterBuilder<URLCreationParameters> builder = URLCreationParameters.builder().name(name).description(description).url(value).on(id).with(ses).author(currentUser);
toReturn = itemHandler.create(builder.build());
} catch (StorageHubException she) {
toReturn = itemHandler.create(builder.build());
}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));
} catch (Throwable e) {
}catch(Throwable e ){
log.error("unexpected error", e);
GXOutboundErrorResponse.throwException(new BackendGenericError(e));
} finally {
if (ses != null)
}finally{
if (ses!=null)
ses.logout();
}
return Response.ok(toReturn).build();
}
@Ignore
@POST
@Consumes(MediaType.APPLICATION_JSON)
@Path("/{id}/create/GCUBEITEM")
@ -239,57 +187,39 @@ public class ItemsCreator extends Impersonable {
Session ses = null;
String toReturn = null;
try {
try{
ses = repository.getRepository().login(Constants.JCR_CREDENTIALS);
ItemsParameterBuilder<GCubeItemCreationParameters> builder = GCubeItemCreationParameters.builder()
.item(item).on(id).with(ses).author(currentUser);
ItemsParameterBuilder<GCubeItemCreationParameters> builder = GCubeItemCreationParameters.builder().item(item).on(id).with(ses).author(currentUser);
toReturn = itemHandler.create(builder.build());
} catch (StorageHubException she) {
toReturn = itemHandler.create(builder.build());
}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));
} catch (Throwable e) {
}catch(Throwable e ){
log.error("unexpected error", e);
GXOutboundErrorResponse.throwException(new BackendGenericError(e));
} finally {
if (ses != null)
}finally{
if (ses!=null)
ses.logout();
}
return toReturn;
}
/**
* Upload a file retrieved from the provided url.
*
* @param id destination folder id
* @param name destination file name
* @param description description meta-info for the created file
* @param url address of the file to be uploaded
* @return id of the created file
* @responseExample text/plain 5f4b3b4e-4b3b- ... -4b3b4e4b3b4e
*/
@DocumentationExample(" ...\n\nname=d4science_logo.png&description=D4Science+logo&url=\"https://www.d4science.org/image/layout_set_logo?img_id=12630&t=1720538711657\"")
@POST
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
@Produces(MediaType.TEXT_PLAIN)
@StatusCodes({
@ResponseCode ( code = 200, condition = "File created."),
@ResponseCode ( code = 400, condition = "Wrong set of parameters."),
@ResponseCode ( code = 406, condition = "Unable to create file."),
@ResponseCode ( code = 415, condition = "Wrong content type."),
})
@Path("/{id}/create/FILE")
public String createFileItemFromUrl(@PathParam("id") String id, @FormParam("name") String name,
@FormParam("description") String description,
@FormParam("url") String url) {
@FormParam("url") String url){
InnerMethodName.set("createItem(FILEFromUrl)");
Session ses = null;
String toReturn = null;
try {
try{
log.debug("UPLOAD: call started");
ses = repository.getRepository().login(Constants.JCR_CREDENTIALS);
@ -298,25 +228,24 @@ public class ItemsCreator extends Impersonable {
long fileLength = connectionURL.getContentLengthLong();
try (InputStream stream = connectionURL.getInputStream()) {
ItemsParameterBuilder<FileCreationParameters> builder = FileCreationParameters.builder().name(name)
.fileDetails(FormDataContentDisposition.name(name).size(fileLength).build())
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());
toReturn = itemHandler.create(builder.build());
}
log.debug("UPLOAD: call finished");
} catch (RepositoryException re) {
}catch(RepositoryException re ){
log.error("jcr error creating file item", re);
GXOutboundErrorResponse.throwException(new BackendGenericError("jcr error creating file item", re));
} catch (StorageHubException she) {
}catch(StorageHubException she ){
log.error(she.getErrorMessage(), she);
GXOutboundErrorResponse.throwException(she, Response.Status.fromStatusCode(she.getStatus()));
} catch (Throwable e) {
}catch(Throwable e ){
log.error("unexpected error", e);
GXOutboundErrorResponse.throwException(new BackendGenericError(e));
} finally {
if (ses != null && ses.isLive()) {
}finally{
if (ses!=null && ses.isLive()) {
log.info("session closed");
ses.logout();
}
@ -325,71 +254,39 @@ public class ItemsCreator extends Impersonable {
}
/**
* Upload the provided file.
*
* @param id destination folder id
* @param name destination file name
* @param description description meta-info for the created file
* @param file multipart/form-data file parameter, with optional
* 'filename' and 'size' (see example below)
* @return id of the created file
* @responseExample text/plain 5f4b3b4e-4b3b- ... -4b3b4e4b3b4e
*/
@ResourceMethodSignature(output = String.class, pathParams = { @PathParam("id") }, formParams = {
@FormParam("name"), @FormParam("description"), @FormParam("file") })
@DocumentationExample(value = "...\n\n--------boundaryString\n" +
"Content-Disposition: form-data; name=\"file\"; filename=\"doc.pdf\"; size=426018;\n" +
"Content-Type: application/pdf\n\n" +
"(data)\n" +
"--------boundaryString\n" +
"Content-Disposition: form-data; name=\"name\"\n\n" +
"doc.pdf\n" +
"--------boundaryString\n" +
"Content-Disposition: form-data; name=\"description\"\n\n" +
"\"This is just a sample PDF file\"\n" +
"--------boundaryString--")
@POST
@Consumes(MediaType.MULTIPART_FORM_DATA)
@Produces(MediaType.TEXT_PLAIN)
@StatusCodes({
@ResponseCode ( code = 200, condition = "File created."),
@ResponseCode ( code = 400, condition = "Wrong set of parameters."),
@ResponseCode ( code = 406, condition = "Unable to create file."),
@ResponseCode ( code = 415, condition = "Wrong content type."),
})
@Path("/{id}/create/FILE")
public String createFileItem(@PathParam("id") String id, @FormDataParam("name") String name,
@FormDataParam("description") String description,
@FormDataParam("file") InputStream file,
@FormDataParam("file") FormDataContentDisposition fileDetail) {
@FormDataParam("file") FormDataContentDisposition fileDetail){
InnerMethodName.set("createItem(FILE)");
Session ses = null;
String toReturn = null;
try (InputStream is = new BufferedInputStream(file)) {
try(InputStream is = new BufferedInputStream(file)){
long size = fileDetail.getSize();
log.info("UPLOAD: call started with file size {}", size);
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(file).fileDetails(fileDetail)
ItemsParameterBuilder<FileCreationParameters> builder = FileCreationParameters.builder().name(name).description(description).stream(file).fileDetails(fileDetail)
.on(id).with(ses).author(currentUser);
log.debug("UPLOAD: item prepared");
toReturn = itemHandler.create(builder.build());
toReturn = itemHandler.create(builder.build());
log.debug("UPLOAD: call finished");
} catch (RepositoryException re) {
}catch(RepositoryException re ){
log.error("jcr error creating file item", re);
GXOutboundErrorResponse.throwException(new BackendGenericError("jcr error creating file item", re));
} catch (StorageHubException she) {
}catch(StorageHubException she ){
log.error(she.getErrorMessage(), she);
GXOutboundErrorResponse.throwException(she, Response.Status.fromStatusCode(she.getStatus()));
} catch (Throwable e) {
}catch(Throwable e ){
log.error("unexpected error", e);
GXOutboundErrorResponse.throwException(new BackendGenericError(e));
} finally {
if (ses != null && ses.isLive()) {
}finally{
if (ses!=null && ses.isLive()) {
log.info("session closed");
ses.logout();
}
@ -398,123 +295,79 @@ public class ItemsCreator extends Impersonable {
}
/**
* Upload an archive from the provided url and extract its content on-the-fly in a new folder.
*
* @param id destination folder id
* @param parentFolderName name of the newly-created folder containing extracted
* files
* @param url address of the archive to be uploaded
* @return id of the created folder containing extracted files
* @responseExample text/plain 5f4b3b4e-4b3b- ... -4b3b4e4b3b4e
*/
@DocumentationExample(" ...\n\nname=sampleZip.zip&description=This+is+a+sample+zip&url=\"https://getsamplefiles.com/download/zip/sample-1.zip\"")
@POST
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
@Produces(MediaType.TEXT_PLAIN)
@StatusCodes({
@ResponseCode ( code = 200, condition = "Archive extracted."),
@ResponseCode ( code = 400, condition = "Wrong set of parameters."),
@ResponseCode ( code = 406, condition = "Unable to extract archive."),
@ResponseCode ( code = 415, condition = "Wrong content type."),
})
@Path("/{id}/create/ARCHIVE")
public String uploadArchiveFromURL(@PathParam("id") String id,
@FormParam("parentFolderName") String parentFolderName,
@FormParam("url") String url) {
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 {
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)
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());
toReturn = itemHandler.create(builder.build());
}
} catch (RepositoryException | ArchiveException | IOException re) {
}catch(RepositoryException | ArchiveException | IOException re){
log.error("jcr error extracting archive", re);
GXOutboundErrorResponse.throwException(new BackendGenericError("jcr error extracting archive", re));
} catch (StorageHubException she) {
}catch(StorageHubException she ){
log.error(she.getErrorMessage(), she);
GXOutboundErrorResponse.throwException(she, Response.Status.fromStatusCode(she.getStatus()));
} catch (Throwable e) {
}catch(Throwable e ){
log.error("unexpected error", e);
GXOutboundErrorResponse.throwException(new BackendGenericError(e));
} finally {
if (ses != null)
} finally{
if (ses!=null)
ses.logout();
}
return toReturn;
}
/**
* Upload the provided archive and extract its content on-the-fly in a new folder.
*
* @param id destination folder id
* @param parentFolderName name of the newly-created folder containing extracted
* files
* @param file multipart/form-data file parameter, with optional
* 'filename' and 'size' (see example below)
* @return id of the created folder containing extracted files
* @responseExample text/plain 5f4b3b4e-4b3b- ... -4b3b4e4b3b4e
*/
@ResourceMethodSignature(output = String.class, pathParams = { @PathParam("id") }, formParams = {
@FormParam("parentFolderName"), @FormParam("file") })
@DocumentationExample(value = "...\n\n--------boundaryString\n" +
"Content-Disposition: form-data; name=\"file\"; filename=\"archive.zip\"; size=1560238;\n" +
"Content-Type: application/zip\n\n" +
"(compressed data)\n" +
"--------boundaryString\n" +
"Content-Disposition: form-data; name=\"parentFolderName=\"\n\n" +
"my documents\n" +
"--------boundaryString--")
@POST
@Consumes(MediaType.MULTIPART_FORM_DATA)
@Produces(MediaType.TEXT_PLAIN)
@StatusCodes({
@ResponseCode ( code = 200, condition = "Archive extracted."),
@ResponseCode ( code = 400, condition = "Wrong set of parameters."),
@ResponseCode ( code = 406, condition = "Unable to extract archive."),
@ResponseCode ( code = 415, condition = "Wrong content type."),
})
@Path("/{id}/create/ARCHIVE")
public String uploadArchive(@PathParam("id") String id, @FormDataParam("parentFolderName") String parentFolderName,
@FormDataParam("file") InputStream file,
@FormDataParam("file") FormDataContentDisposition fileDetail) {
@FormDataParam("file") InputStream stream,
@FormDataParam("file") FormDataContentDisposition fileDetail){
InnerMethodName.set("createItem(ARCHIVE)");
Session ses = null;
String toReturn = null;
try (InputStream is = new BufferedInputStream(file)) {
try(InputStream is = new BufferedInputStream(stream)){
ses = repository.getRepository().login(Constants.JCR_CREDENTIALS);
ItemsParameterBuilder<ArchiveStructureCreationParameter> builder = ArchiveStructureCreationParameter
.builder().parentName(parentFolderName).stream(is).fileDetails(fileDetail)
ItemsParameterBuilder<ArchiveStructureCreationParameter> builder = ArchiveStructureCreationParameter.builder().parentName(parentFolderName).stream(is).fileDetails(fileDetail)
.on(id).with(ses).author(currentUser);
toReturn = itemHandler.create(builder.build());
toReturn = itemHandler.create(builder.build());
} catch (RepositoryException | ArchiveException | IOException re) {
}catch(RepositoryException | ArchiveException | IOException re){
log.error("jcr error extracting archive", re);
GXOutboundErrorResponse.throwException(new BackendGenericError("jcr error extracting archive", re));
} catch (StorageHubException she) {
}catch(StorageHubException she ){
log.error(she.getErrorMessage(), she);
GXOutboundErrorResponse.throwException(she, Response.Status.fromStatusCode(she.getStatus()));
} catch (Throwable e) {
}catch(Throwable e ){
log.error("unexpected error", e);
GXOutboundErrorResponse.throwException(new BackendGenericError(e));
} finally {
if (ses != null)
} finally{
if (ses!=null)
ses.logout();
}
return toReturn;
}
}

View File

@ -63,13 +63,8 @@ import org.gcube.smartgears.utils.InnerMethodName;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.webcohesion.enunciate.metadata.DocumentationExample;
import com.webcohesion.enunciate.metadata.Ignore;
import com.webcohesion.enunciate.metadata.rs.RequestHeader;
import com.webcohesion.enunciate.metadata.rs.RequestHeaders;
import com.webcohesion.enunciate.metadata.rs.ResourceMethodSignature;
import com.webcohesion.enunciate.metadata.rs.ResponseCode;
import com.webcohesion.enunciate.metadata.rs.StatusCodes;
import jakarta.inject.Inject;
import jakarta.servlet.ServletContext;
@ -87,13 +82,11 @@ import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.core.Response.Status;
/**
* Manage item retrieval, deletion, and update.
*/
@Path("items")
@ManagedBy(StorageHubApplicationManager.class)
@RequestHeaders({
@RequestHeader( name = "Authorization", description = "Bearer token, see <a href=\"https://dev.d4science.org/how-to-access-resources\">https://dev.d4science.org/how-to-access-resources</a>"),
@RequestHeader( name = "Authorization", description = "Bearer token, see https://dev.d4science.org/how-to-access-resources"),
})
public class ItemsManager extends Impersonable{
@ -137,22 +130,7 @@ public class ItemsManager extends Impersonable{
PublicLinkHandler publicLinkHandler;
/**
* Retrieve an item by its id.
*
* @param id item id
* @param exclude a list of fields to exclude from the returned item<br>
* <strong>Multivalued</strong><br>
* <strong>Optional</strong>
* @return a JSON representation of the item
* @pathExample /{id}?exclude=content
*/
@ResourceMethodSignature(output = ItemWrapper.class, pathParams = @PathParam("id"), queryParams = @QueryParam("exclude"))
@GET
@StatusCodes({
@ResponseCode ( code = 200, condition = "Item found."),
@ResponseCode ( code = 406, condition = "Unable to find this item."),
})
@Path("{id}")
@Produces(MediaType.APPLICATION_JSON)
public ItemWrapper<Item> getById(@QueryParam("exclude") List<String> excludes){
@ -181,18 +159,6 @@ public class ItemsManager extends Impersonable{
return new ItemWrapper<Item>(toReturn);
}
/**
* Retrieve an item by its relative path.
*
* @param id item id
* @param path the relative path of the item to retrieve
* @param exclude a list of fields to exclude from the returned item<br>
* <strong>Multivalued</strong><br>
* <strong>Optional</strong>
* @return a JSON representation of the item
* @pathExample /{id}/path?path=folder1&exclude=content
*/
@ResourceMethodSignature(output = ItemWrapper.class, pathParams = @PathParam("id"), queryParams = {@QueryParam("path"), @QueryParam("exclude")})
@GET
@Path("{id}/path")
@Produces(MediaType.APPLICATION_JSON)
@ -254,7 +220,6 @@ public class ItemsManager extends Impersonable{
return null;
}
@Ignore
@Deprecated
@GET
@Path("{id}/items/{name}")
@ -264,22 +229,6 @@ public class ItemsManager extends Impersonable{
return _findChildrenByNamePattern(excludes, name);
}
/**
* Retrieve a child item by its name.
*
* @param id parent item id
* @param exclude a list of fields to exclude from the returned item<br>
* <strong>Multivalued</strong><br>
* <strong>Optional</strong>
* @param name the name of the child item to retrieve
* @return a JSON representation of the item list
* @pathExample /{id}/items?name=doc.pdf&exclude=content
*/
@ResourceMethodSignature(output = String.class, pathParams = { @PathParam("id") }, queryParams = { @QueryParam("exclude"), @QueryParam("name") })
@StatusCodes({
@ResponseCode ( code = 200, condition = "Item found."),
@ResponseCode ( code = 406, condition = "Parent item does not exist."),
})
@GET
@Path("{id}/items")
@Produces(MediaType.APPLICATION_JSON)
@ -329,26 +278,9 @@ public class ItemsManager extends Impersonable{
}
/**
* Retrieve a child item by its name.
*
* @param id parent item id
* @param showHidden if true, hidden items are shown<br>
* <strong>Possible values:</strong> <code>true</code>, <code>false</code> <br>
* <strong>Optional</strong> default: <code>false</code>
* @param onlyType only items of the specified type are counted <br>
* <strong>Optional</strong>
* @return the number of children
* @pathExample /{id}/children/count?showHidden=true&onlyType=File
*/
@ResourceMethodSignature(output = Long.class, pathParams = @PathParam("id"), queryParams = {@QueryParam("showHidden"), @QueryParam("onlyType")})
@StatusCodes({
@ResponseCode ( code = 200, condition = "Item found."),
@ResponseCode ( code = 406, condition = "Parent item does not exist"),
})
@GET
@Path("{id}/children/count")
public Long countById(@QueryParam("showHidden") Boolean showHidden, @QueryParam("onlyType") String nodeType){
public Long countById(@QueryParam("showHidden") Boolean showHidden, @QueryParam("exclude") List<String> excludes, @QueryParam("onlyType") String nodeType){
InnerMethodName.set("countById");
Session ses = null;
Long toReturn = null;
@ -375,26 +307,6 @@ public class ItemsManager extends Impersonable{
return toReturn ;
}
/**
* Retrieve a list of children items.
*
* @param id parent item id
* @param exclude a list of fields to exclude from the returned item<br>
* <strong>Multivalued</strong><br>
* <strong>Optional</strong>
* @param showHidden if true, hidden items are shown<br>
* <strong>Possible values:</strong> <code>true</code>, <code>false</code> <br>
* <strong>Optional</strong> default: <code>false</code>
* @param onlyType only items of the specified type are counted <br>
* <strong>Optional</strong>
* @return a JSON representation of the item list
* @pathExample /{id}/children?showHidden=true&onlyType=File&exclude=content
*/
@ResourceMethodSignature(output = ItemList.class, pathParams = @PathParam("id"), queryParams = {@QueryParam("showHidden"), @QueryParam("exclude"), @QueryParam("onlyType")})
@StatusCodes({
@ResponseCode ( code = 200, condition = "Item found."),
@ResponseCode ( code = 406, condition = "Parent item does not exist."),
})
@GET
@Path("{id}/children")
@Produces(MediaType.APPLICATION_JSON)
@ -425,9 +337,6 @@ public class ItemsManager extends Impersonable{
return new ItemList(toReturn);
}
// tipo di nodo ROOT - per ora non funziona
@Ignore
@GET
@Path("{id}/search")
@Produces(MediaType.APPLICATION_JSON)
@ -460,32 +369,6 @@ public class ItemsManager extends Impersonable{
return new ItemList(toReturn);
}
/**
* Retrieve a paged list of children items.
*
* @param id parent item id
* @param exclude a list of fields to exclude from the returned item<br>
* <strong>Multivalued</strong><br>
* <strong>Optional</strong>
* @param showHidden if true, hidden items are shown<br>
* <strong>Possible values:</strong> <code>true</code>, <code>false</code> <br>
* <strong>Optional</strong> default: <code>false</code>
* @param onlyType only items of the specified type are counted <br>
* <strong>Optional</strong>
* @param start start index, counting from 0 <br>
* <strong>Possible values:</strong> integers
* @param limit maximum number of items returned <br>
* <strong>Possible values:</strong> integers
* @return a JSON representation of the item list
* @pathExample /{id}/children/paged?start=1&limit=100&showHidden=true&onlyType=File&exclude=content
*/
@ResourceMethodSignature(output = ItemList.class, pathParams = @PathParam("id"),
queryParams = {@QueryParam("showHidden"), @QueryParam("exclude"), @QueryParam("onlyType"), @QueryParam("start"), @QueryParam("limit")})
@StatusCodes({
@ResponseCode ( code = 200, condition = "Item found."),
@ResponseCode ( code = 406, condition = "Parent item does not exist."),
@ResponseCode ( code = 500, condition = "Missing 'start' or 'limit' parameter."),
})
@GET
@Path("{id}/children/paged")
@Produces(MediaType.APPLICATION_JSON)
@ -516,7 +399,6 @@ public class ItemsManager extends Impersonable{
return new ItemList(toReturn);
}
@Ignore
@GET
@Path("publiclink/{id}")
@AuthorizationControl(allowedUsers={"URIResolver"})
@ -552,21 +434,6 @@ public class ItemsManager extends Impersonable{
return Response.serverError().build();
}
/**
* Retrieves the public link for a specified item.
*
* @param id item id
* @param version version of the item for which the public link is requested <br>
* <strong>Optional</strong> default: <em>last version</em>
* @return URL of the public link for the specified item
* @pathExample /{id}/publiclink?version=1.0
*/
@ResourceMethodSignature(output = URL.class, pathParams = @PathParam("id"), queryParams = @QueryParam("version"))
@StatusCodes({
@ResponseCode ( code = 200, condition = "Item found."),
@ResponseCode ( code = 400, condition = "This item is not a file."),
@ResponseCode ( code = 406, condition = "Item does not exist."),
})
@GET
@Produces(MediaType.APPLICATION_JSON)
@Path("{id}/publiclink")
@ -630,21 +497,6 @@ public class ItemsManager extends Impersonable{
/**
* Set the access level of the specified folder.
*
* @param id item id
* @param publish if true, the folder is made public <br>
* <strong>Possible values:</strong> <code>true</code>, <code>false</code>
* @return the id of the folder
*/
@ResourceMethodSignature(output = String.class, pathParams = @PathParam("id"), formParams = @FormParam("publish"))
@DocumentationExample("...\n\npublish=true")
@StatusCodes({
@ResponseCode ( code = 200, condition = "Item found."),
@ResponseCode ( code = 400, condition = "This item is not a file."),
@ResponseCode ( code = 406, condition = "Item does not exist."),
})
@PUT
@Path("{id}/publish")
@Produces(MediaType.APPLICATION_JSON)
@ -681,21 +533,6 @@ public class ItemsManager extends Impersonable{
}
/**
* Retrieves the root shared folder for the specified item.
*
* @param id item id
* @param exclude a list of fields to exclude from the returned item<br>
* <strong>Multivalued</strong><br>
* <strong>Optional</strong>
* @return the id of the root folder
*/
@StatusCodes({
@ResponseCode ( code = 200, condition = "Item found."),
@ResponseCode ( code = 400, condition = "This item is not a shared."),
@ResponseCode ( code = 406, condition = "Item does not exist."),
})
@ResourceMethodSignature(output = ItemWrapper.class, pathParams = @PathParam("id"), queryParams = @QueryParam("exclude"))
@GET
@Path("{id}/rootSharedFolder")
@Produces(MediaType.APPLICATION_JSON)
@ -739,17 +576,6 @@ public class ItemsManager extends Impersonable{
return currentNode;
}
/**
* Retrieves the list of versions for the specified item.
*
* @param id item id
* @return the version list
*/
@StatusCodes({
@ResponseCode ( code = 200, condition = "Item found."),
@ResponseCode ( code = 406, condition = "Item does not exist."),
})
@ResourceMethodSignature(output = VersionList.class, pathParams = @PathParam("id"))
@GET
@Path("{id}/versions")
@Produces(MediaType.APPLICATION_JSON)
@ -787,20 +613,6 @@ public class ItemsManager extends Impersonable{
return new VersionList(versions);
}
/**
* Download a specific version of a given item.
*
* @param id item id
* @param version the requested version
* @return download the item
* @pathExample /{id}/versions/1.0/download
*/
@ResourceMethodSignature(output = String.class, pathParams = { @PathParam("id") })
@StatusCodes({
@ResponseCode ( code = 200, condition = "Item found."),
@ResponseCode ( code = 406, condition = "Item does not exist."),
@ResponseCode ( code = 500, condition = "Invalid version."),
})
@GET
@Path("{id}/versions/{version}/download")
public Response downloadVersion(@PathParam("version") String versionName){
@ -829,21 +641,6 @@ public class ItemsManager extends Impersonable{
return Response.serverError().build();
}
/**
* Delete a specific version of a given item.
*
* @param id item id
* @param version the requested version
* @return download the item
* @pathExample /{id}/versions/1.0
*/
@ResourceMethodSignature(output = void.class, pathParams = { @PathParam("id"), @PathParam("version") })
@StatusCodes({
@ResponseCode ( code = 200, condition = "Item deleted."),
@ResponseCode ( code = 400, condition = "This item's version cannot be removed."),
@ResponseCode ( code = 406, condition = "Item does not exist."),
@ResponseCode ( code = 500, condition = "Invalid version."),
})
@DELETE
@Path("{id}/versions/{version}")
public void deleteVersion(@PathParam("version") String versionName){
@ -887,21 +684,6 @@ public class ItemsManager extends Impersonable{
}
/**
* Retrieve the anchestors of a given item.
*
* @param id item id
* @param exclude a list of fields to exclude from the returned item list<br>
* <strong>Multivalued</strong> <br>
* <strong>Optional</strong>
* @return the list of anchestors
* @pathExample /{id}/anchestors?exclude=content
*/
@ResourceMethodSignature(output = ItemList.class, pathParams = { @PathParam("id")}, queryParams = { @QueryParam("exclude")})
@StatusCodes({
@ResponseCode ( code = 200, condition = "Item found."),
@ResponseCode ( code = 406, condition = "Item does not exist."),
})
@GET
@Path("{id}/anchestors")
@Produces(MediaType.APPLICATION_JSON)
@ -959,21 +741,9 @@ public class ItemsManager extends Impersonable{
/**
* Download a given item.
*
* @param id item id
* @return download the item
* @pathExample /{id}/download
*/
@ResourceMethodSignature(output = Response.class, pathParams = { @PathParam("id")})
@StatusCodes({
@ResponseCode ( code = 200, condition = "Item found."),
@ResponseCode ( code = 406, condition = "Item does not exist."),
})
@GET
@Path("{id}/download")
public Response download(){
public Response download(@QueryParam("exclude") List<String> excludes){
InnerMethodName.set("downloadById");
Session ses = null;
try{
@ -1000,22 +770,6 @@ public class ItemsManager extends Impersonable{
}
/**
* Move a given item.
*
* @param id item id
* @param destinationId destination folder id
* @return id of the moved item
* @pathExample /{id}/move
* @responseExample text/plain 5f4b3b4e-4b3b- ... -4b3b4e4b3b4e
*/
@ResourceMethodSignature(output = String.class, pathParams = { @PathParam("id") }, formParams = { @FormParam("destinationId")})
@DocumentationExample("...\n\ndestinationId=19863b4e-b33f- ... -5b6d2e0e1eee")
@StatusCodes({
@ResponseCode ( code = 200, condition = "Item moved."),
@ResponseCode ( code = 406, condition = "Source or destination item does not exist."),
@ResponseCode ( code = 409, condition = "Source and destination are the same item."),
})
@PUT
@Path("{id}/move")
public String move(@FormParam("destinationId") String destinationId){
@ -1094,23 +848,6 @@ public class ItemsManager extends Impersonable{
return id;
}
/**
* Copy a given item.
*
* @param id item id
* @param destinationId destination folder id
* @param fileName name of the copied item
* @return id of the copied item
* @pathExample /{id}/copy
* @responseExample text/plain 5f4b3b4e-4b3b- ... -4b3b4e4b3b4e
*/
@ResourceMethodSignature(output = String.class, pathParams = @PathParam("id"),
formParams = { @FormParam("destinationId"), @FormParam("fileName")})
@DocumentationExample("...\n\ndestinationId=19863b4e-b33f- ... -5b6d2e0e1eee&fileName=myCopy.jpg")
@StatusCodes({
@ResponseCode ( code = 200, condition = "Item copied."),
@ResponseCode ( code = 406, condition = "Source or destination item does not exist."),
})
@PUT
@Path("{id}/copy")
public String copy(@FormParam("destinationId") String destinationId, @FormParam("fileName") String newFileName){
@ -1186,21 +923,6 @@ public class ItemsManager extends Impersonable{
return newFileIdentifier;
}
/**
* Rename a given item.
*
* @param id item id
* @param newName new name for the item
* @return id of the renamed item
* @pathExample /{id}/rename
* @responseExample text/plain 5f4b3b4e-4b3b- ... -4b3b4e4b3b4e
*/
@ResourceMethodSignature(output = String.class, pathParams = @PathParam("id"), formParams = @FormParam("newName"))
@DocumentationExample("...\n\nnewName=newFileName.txt")
@StatusCodes({
@ResponseCode ( code = 200, condition = "Item renamed."),
@ResponseCode ( code = 406, condition = "Item does not exist."),
})
@PUT
@Path("{id}/rename")
public Response rename(@FormParam("newName") String newName){
@ -1257,25 +979,9 @@ public class ItemsManager extends Impersonable{
return Response.ok(id).build();
}
/**
* Set the item as hidden or visible. The body request is interpreted as the boolean
* value for the visibility.
*
* @param id item id
* @return id of the item
* @pathExample /{id}/hidden
* @responseExample text/plain 5f4b3b4e-4b3b- ... -4b3b4e4b3b4e
*/
@ResourceMethodSignature(output = String.class, pathParams = { @PathParam("id") })
@DocumentationExample("...\n\ntrue")
@StatusCodes({
@ResponseCode ( code = 200, condition = "Item visibility set."),
@ResponseCode ( code = 400, condition = "Unable to parse request body."),
@ResponseCode ( code = 406, condition = "Item does not exist."),
})
//TODO: transform this and setMetadata in a generic method for all properties
@PUT
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.TEXT_PLAIN)
@Path("/{id}/hidden")
public Response setItemAsHidden(Boolean hidden){
InnerMethodName.set("setHidden");
@ -1318,24 +1024,9 @@ public class ItemsManager extends Impersonable{
return Response.ok(id).build();
}
/**
* Set description for the specified item. The body request is interpreted as the description string.
*
* @param id item id
* @return id of the item
* @pathExample /{id}/description
* @responseExample text/plain 5f4b3b4e-4b3b- ... -4b3b4e4b3b4e
*/
@ResourceMethodSignature(output = String.class, pathParams = { @PathParam("id") })
@DocumentationExample("...\n\nThis is a sample description")
@StatusCodes({
@ResponseCode ( code = 200, condition = "Item description set."),
@ResponseCode ( code = 400, condition = "Unable to parse request body."),
@ResponseCode ( code = 406, condition = "Item does not exist."),
})
//TODO: transform this and setMetadata in a generic method for all properties
@PUT
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.TEXT_PLAIN)
@Path("/{id}/description")
public Response setDescription(String description){
InnerMethodName.set("setDescription");
@ -1378,29 +1069,8 @@ public class ItemsManager extends Impersonable{
return Response.ok(id).build();
}
/**
* Set metadata for the specified item. The body request is interpreted as the metadata JSON.
*
* @param id item id
* @return id of the item
* @pathExample /{id}/metadata
* @responseExample text/plain 5f4b3b4e-4b3b- ... -4b3b4e4b3b4e
*/
@ResourceMethodSignature(output = String.class, pathParams = { @PathParam("id") })
@DocumentationExample("...\n\n{\n" +
" \"map\": {\n" +
" \"meta1\": \"value1\",\n" +
" \"meta2\": \"value2\"\n" +
" }\n" +
"}")
@StatusCodes({
@ResponseCode ( code = 200, condition = "Item metadata set."),
@ResponseCode ( code = 400, condition = "Unable to parse request body."),
@ResponseCode ( code = 406, condition = "Item does not exist."),
})
@PUT
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.TEXT_PLAIN)
@Path("/{id}/metadata")
public Response setMetadata(org.gcube.common.storagehub.model.Metadata metadata){
InnerMethodName.set("updateMetadata");
@ -1445,22 +1115,7 @@ public class ItemsManager extends Impersonable{
/**
* Move the specified item to the trash or delete it permanently if it is already trashed.
*
* @param id item id
* @param force permanently delete <br>
* <strong>Possible values:</strong> <code>true</code>, <code>false</code> <br>
* <strong>Optional</strong> default: <code>false</code>
* @pathExample /{id}?force=true
*/
@ResourceMethodSignature (output = String.class, pathParams = { @PathParam("id") }, queryParams = { @QueryParam("force") })
@DELETE
@StatusCodes({
@ResponseCode ( code = 200, condition = "Item deleted."),
@ResponseCode ( code = 406, condition = "Unable to find this item."),
@ResponseCode ( code = 500, condition = "Unable to delete this item."),
})
@Path("{id}")
public Response deleteItem(@QueryParam("force") boolean force){
InnerMethodName.set("deleteItem("+force+")");
@ -1508,18 +1163,6 @@ public class ItemsManager extends Impersonable{
return Response.ok().build();
}
/**
* Get info of the specified folder.
*
* @param id item id
* @return folder info
*/
@ResourceMethodSignature(output = String.class, pathParams = { @PathParam("id") })
@StatusCodes({
@ResponseCode ( code = 200, condition = "Item found."),
@ResponseCode ( code = 400, condition = "This item is not a folder."),
@ResponseCode ( code = 406, condition = "Unable to find this folder."),
})
@Path("{id}/info")
@GET
@Produces(MediaType.APPLICATION_JSON)

View File

@ -52,7 +52,6 @@ import org.gcube.smartgears.utils.InnerMethodName;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.webcohesion.enunciate.metadata.Ignore;
import com.webcohesion.enunciate.metadata.rs.RequestHeader;
import com.webcohesion.enunciate.metadata.rs.RequestHeaders;
@ -72,11 +71,10 @@ import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.core.Response.Status;
@Ignore
@Path("messages")
@ManagedBy(StorageHubApplicationManager.class)
@RequestHeaders({
@RequestHeader( name = "Authorization", description = "Bearer token, see <a href=\"https://dev.d4science.org/how-to-access-resources\">https://dev.d4science.org/how-to-access-resources</a>"),
@RequestHeader( name = "Authorization", description = "Bearer token, see https://dev.d4science.org/how-to-access-resources"),
})
public class MessageManager extends Impersonable{

View File

@ -11,8 +11,6 @@ import org.gcube.smartgears.utils.InnerMethodName;
import com.webcohesion.enunciate.metadata.rs.RequestHeader;
import com.webcohesion.enunciate.metadata.rs.RequestHeaders;
import com.webcohesion.enunciate.metadata.rs.ResponseCode;
import com.webcohesion.enunciate.metadata.rs.StatusCodes;
import jakarta.inject.Inject;
import jakarta.ws.rs.GET;
@ -20,28 +18,17 @@ import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;
/**
* Manage underlying storage backends.
*/
@Path("storages")
@ManagedBy(StorageHubApplicationManager.class)
@RequestHeaders({
@RequestHeader( name = "Authorization", description = "Bearer token, see <a href=\"https://dev.d4science.org/how-to-access-resources\">https://dev.d4science.org/how-to-access-resources</a>"),
@RequestHeader( name = "Authorization", description = "Bearer token, see https://dev.d4science.org/how-to-access-resources"),
})
public class StorageManager {
@Inject
StorageBackendHandler storageBackendHandler;
/**
* Get a list of available storages
*
* @return list of available storages
*/
@GET
@StatusCodes({
@ResponseCode ( code = 200, condition = "Success."),
})
@Path("/")
@Produces(MediaType.APPLICATION_JSON)
public List<StorageDescriptor> getStorages(){

View File

@ -22,11 +22,8 @@ import org.gcube.smartgears.utils.InnerMethodName;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.webcohesion.enunciate.metadata.DocumentationExample;
import com.webcohesion.enunciate.metadata.rs.RequestHeader;
import com.webcohesion.enunciate.metadata.rs.RequestHeaders;
import com.webcohesion.enunciate.metadata.rs.ResponseCode;
import com.webcohesion.enunciate.metadata.rs.StatusCodes;
import jakarta.inject.Inject;
import jakarta.ws.rs.Consumes;
@ -41,13 +38,10 @@ import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
/**
* Manage users
*/
@Path("users")
@ManagedBy(StorageHubApplicationManager.class)
@RequestHeaders({
@RequestHeader(name = "Authorization", description = "Bearer token, see <a href=\"https://dev.d4science.org/how-to-access-resources\">https://dev.d4science.org/how-to-access-resources</a>"), })
@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";
@ -59,15 +53,7 @@ public class UserManager {
@Inject
UserManagerDelegate userHandler;
/**
* Get a list of users
*
* @return list of users
*/
@GET
@StatusCodes({
@ResponseCode ( code = 200, condition = "Success."),
})
@Path("")
@Produces(MediaType.APPLICATION_JSON)
public UsersList getUsers() {
@ -86,17 +72,7 @@ public class UserManager {
return null;
}
/**
* Get user details
*
* @param user user name
* @return user detail
*/
@GET
@StatusCodes({
@ResponseCode ( code = 200, condition = "User found."),
@ResponseCode ( code = 406, condition = "User does not exist."),
})
@Path("{user}")
@Produces(MediaType.APPLICATION_JSON)
public SHUBUser getUser(@PathParam("user") String user) {
@ -124,26 +100,9 @@ public class UserManager {
return null;
}
/**
* Create a new user <br>
* <strong>Only users with <code>Infrastructure-Manager</code> role allowed</strong>
*
* @param user user name
* @param password user password
* @return user name
* @responseExample name.surname
*/
@DocumentationExample(" ...\n\nuser=nome.utente&password=passw0rd")
@POST
@StatusCodes({
@ResponseCode ( code = 200, condition = "User created."),
@ResponseCode ( code = 400, condition = "Wrong set of parameters."),
@ResponseCode ( code = 403, condition = "You're not allowed to create users."),
@ResponseCode ( code = 415, condition = "Wrong content type."),
})
@Path("")
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
@Produces(MediaType.TEXT_PLAIN)
@AuthorizationControl(allowedRoles = { INFRASTRUCTURE_MANAGER_ROLE })
public String createUser(@FormParam("user") String user, @FormParam("password") String password) {
@ -171,21 +130,9 @@ public class UserManager {
return userId;
}
/**
* Update user to the last 'home' version <br>
* <strong>Only users with <code>Infrastructure-Manager</code> role allowed</strong>
*
* @param user user name
* @return user id
*/
@PUT
@Path("{user}")
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
@StatusCodes({
@ResponseCode ( code = 200, condition = "Home update done."),
@ResponseCode ( code = 403, condition = "You're not allowed to create users."),
@ResponseCode ( code = 415, condition = "Wrong content type."),
})
@AuthorizationControl(allowedRoles = { INFRASTRUCTURE_MANAGER_ROLE })
public String updateHomeUserToLatestVersion(@PathParam("user") String user) {
@ -213,21 +160,8 @@ public class UserManager {
return userId;
}
/**
* Delete a user <br>
* <strong>Only users with <code>Infrastructure-Manager</code> role allowed</strong>
*
* @param user user name
* @return user name
*/
@DELETE
@StatusCodes({
@ResponseCode ( code = 200, condition = "User deleted."),
@ResponseCode ( code = 403, condition = "You're not allowed to delete users."),
@ResponseCode ( code = 406, condition = "User does not exist."),
})
@Path("{user}")
@Produces(MediaType.TEXT_PLAIN)
@AuthorizationControl(allowedRoles = { INFRASTRUCTURE_MANAGER_ROLE })
public String deleteUser(@PathParam("user") final String user) {
@ -255,17 +189,7 @@ public class UserManager {
return user;
}
/**
* Get a list of groups for the specified user
*
* @param user user name
* @return List of groups
*/
@GET
@StatusCodes({
@ResponseCode ( code = 200, condition = "User found."),
@ResponseCode ( code = 500, condition = "User does not exist."),
})
@Path("{user}/groups")
@Produces(MediaType.APPLICATION_JSON)
public List<String> getGroupsPerUser(@PathParam("user") final String user) {

View File

@ -56,13 +56,8 @@ import org.glassfish.jersey.media.multipart.FormDataParam;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.webcohesion.enunciate.metadata.DocumentationExample;
import com.webcohesion.enunciate.metadata.Ignore;
import com.webcohesion.enunciate.metadata.rs.RequestHeader;
import com.webcohesion.enunciate.metadata.rs.RequestHeaders;
import com.webcohesion.enunciate.metadata.rs.ResourceMethodSignature;
import com.webcohesion.enunciate.metadata.rs.ResponseCode;
import com.webcohesion.enunciate.metadata.rs.StatusCodes;
import jakarta.enterprise.context.RequestScoped;
import jakarta.inject.Inject;
@ -80,13 +75,10 @@ import jakarta.ws.rs.core.Context;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
/**
* Manage the workspace
*/
@Path("/")
@ManagedBy(StorageHubApplicationManager.class)
@RequestHeaders({
@RequestHeader(name = "Authorization", description = "Bearer token, see <a href=\"https://dev.d4science.org/how-to-access-resources\">https://dev.d4science.org/how-to-access-resources</a>"), })
@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);
@ -129,21 +121,6 @@ public class WorkspaceManager extends Impersonable {
@Inject
Item2NodeConverter item2Node;
/**
* Get info of an item referred through its path
*
* @param relPath relative path
* @param exclude a list of fields to exclude from the returned item<br>
* <strong>Multivalued</strong><br>
* <strong>Optional</strong>
* @return workspace item
* @pathExample /?relPath=folder1/folder2/file.txt&exclude=owner
*/
@StatusCodes({
@ResponseCode ( code = 200, condition = "Item retrieved."),
@ResponseCode ( code = 406, condition = "Item not found."),
})
@ResourceMethodSignature(output = ItemWrapper.class, queryParams = { @QueryParam("relPath"), @QueryParam("exclude") })
@Path("/")
@GET
@Produces(MediaType.APPLICATION_JSON)
@ -187,33 +164,19 @@ public class WorkspaceManager extends Impersonable {
}
/**
* Upload a file in the volatile area
* Uploads a file in the volatile area returning a public link
*
* @param file multipart/form-data file parameter, with optional
* 'filename' and 'size' (see example below)
* @param exclude a list of fields to exclude from the returned item<br>
* <strong>Multivalued</strong><br>
* <strong>Optional</strong>
* @return public link to the created file
* @responseExample https://data.dev.d4science.org/shub/VLT_V1...9PQ==
* @param id
* @param name
* @param description
* @param stream
* @param fileDetail
* @return
*/
@ResourceMethodSignature(output = String.class, formParams = { @FormParam("file") }, queryParams = { @QueryParam("exclude") })
@DocumentationExample(value = "...\n\n--------boundaryString\n" +
"Content-Disposition: form-data; name=\"file\"; filename=\"doc.pdf\"; size=426018;\n" +
"Content-Type: application/pdf\n\n" +
"(data)\n" +
"--------boundaryString--")
@POST
@Consumes(MediaType.MULTIPART_FORM_DATA)
@Produces(MediaType.TEXT_PLAIN)
@StatusCodes({
@ResponseCode ( code = 200, condition = "File created."),
@ResponseCode ( code = 400, condition = "File not provided."),
@ResponseCode ( code = 415, condition = "Wrong content type."),
@ResponseCode ( code = 500, condition = "Wrong set of parameters."),
})
@Path("volatile")
public String uploadVolatileFile(@FormDataParam("file") InputStream file,
public String uploadVolatileFile(@FormDataParam("file") InputStream stream,
@FormDataParam("file") FormDataContentDisposition fileDetail) {
InnerMethodName.set("uploadToVolatileArea");
@ -230,7 +193,7 @@ public class WorkspaceManager extends Impersonable {
StorageBackend sb = sbf.create(payloadBackend);
log.info("UPLOAD: call started with file size {}", size);
MetaInfo info = sb.upload(file, null, fileDetail.getFileName(), currentUser);
MetaInfo info = sb.upload(stream, null, fileDetail.getFileName(), currentUser);
log.debug("UPLOAD: call finished");
toReturn = publicLinkHandler.getForVolatile(info.getStorageId(), GCubeVolatileStorageBackendFactory.NAME,
@ -245,23 +208,11 @@ public class WorkspaceManager extends Impersonable {
return toReturn;
}
/**
* Get info on the VRE folder associated to the current token
*
* @param exclude a list of fields to exclude from the returned item<br>
* <strong>Multivalued</strong><br>
* <strong>Optional</strong>
* @return VRE folder info
*/
@ResourceMethodSignature(output = ItemWrapper.class, queryParams = { @QueryParam("exclude") })
@Path("vrefolder")
@GET
@StatusCodes({
@ResponseCode ( code = 200, condition = "Success."),
})
@Produces(MediaType.APPLICATION_JSON)
public ItemWrapper<Item> getCurrentVreFolder() {
InnerMethodName.set("getCurrentVreFolder");
public ItemWrapper<Item> getVreRootFolder() {
InnerMethodName.set("getVreRootFolder");
JackrabbitSession ses = null;
Item vreItem = null;
try {
@ -288,18 +239,6 @@ public class WorkspaceManager extends Impersonable {
return new ItemWrapper<Item>(vreItem);
}
/**
* Get a list of recent documents from VRE folders
*
* @param exclude a list of fields to exclude from the returned item<br>
* <strong>Multivalued</strong><br>
* <strong>Optional</strong>
* @return list of recent documents
*/
@ResourceMethodSignature(output = ItemList.class, queryParams = { @QueryParam("exclude") })
@StatusCodes({
@ResponseCode ( code = 200, condition = "Success."),
})
@Path("vrefolder/recents")
@GET
@Produces(MediaType.APPLICATION_JSON)
@ -338,18 +277,6 @@ public class WorkspaceManager extends Impersonable {
}
/**
* Get info on the trash folder
*
* @param exclude a list of fields to exclude from the returned item<br>
* <strong>Multivalued</strong><br>
* <strong>Optional</strong>
* @return info on the trash folder
*/
@ResourceMethodSignature(output = ItemWrapper.class, queryParams = { @QueryParam("exclude") })
@StatusCodes({
@ResponseCode ( code = 200, condition = "Success."),
})
@Path("trash")
@GET
@Produces(MediaType.APPLICATION_JSON)
@ -380,21 +307,7 @@ public class WorkspaceManager extends Impersonable {
return new ItemWrapper<Item>(item);
}
/**
* Empty the trash folder
*
* @param exclude a list of fields to exclude from the returned item<br>
* <strong>Multivalued</strong><br>
* <strong>Optional</strong>
* @return trash folder id
* @responseExample text/plain 5f4b3b4e-4b3b- ... -4b3b4e4b3b4e
*/
@ResourceMethodSignature(output = String.class, queryParams = { @QueryParam("exclude") })
@StatusCodes({
@ResponseCode ( code = 200, condition = "Trash emptied."),
})
@Path("trash/empty")
@Produces(MediaType.TEXT_PLAIN)
@DELETE
public String emptyTrash() {
InnerMethodName.set("emptyTrash");
@ -421,25 +334,6 @@ public class WorkspaceManager extends Impersonable {
return toReturn;
}
/**
* Restore a trashed item.
*
* @param trashedItemId item id
* @param destinationId destination folder id
* @param exclude a list of fields to exclude from the returned item<br>
* <strong>Multivalued</strong><br>
* <strong>Optional</strong>
* @return id of the restored item
* @responseExample text/plain 5f4b3b4e-4b3b- ... -4b3b4e4b3b4e
*/
@ResourceMethodSignature(output = String.class, queryParams = { @QueryParam("exclude")}, formParams = { @FormParam("trashedItemId"), @FormParam("destinationId") })
@DocumentationExample("...\n\ntrashedId=17dae181-f33c- ... - 3fa22198dd30&destinationId=19863b4e-b33f- ... -5b6d2e0e1eee")
@StatusCodes({
@ResponseCode ( code = 200, condition = "Item restored."),
@ResponseCode ( code = 406, condition = "Source or destination item does not exist."),
@ResponseCode ( code = 409, condition = "Source and destination are the same item."),
@ResponseCode ( code = 415, condition = "Wrong content type."),
})
@PUT
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
@Path("trash/restore")
@ -489,15 +383,6 @@ public class WorkspaceManager extends Impersonable {
return toReturn;
}
/**
* Get a list of VRE folders for which the user is member
*
* @param exclude a list of fields to exclude from the returned item<br>
* <strong>Multivalued</strong><br>
* <strong>Optional</strong>
* @return list of VRE folders
*/
@ResourceMethodSignature(output = ItemList.class, queryParams = { @QueryParam("exclude") })
@Path("vrefolders")
@GET
@Produces(MediaType.APPLICATION_JSON)
@ -526,20 +411,6 @@ public class WorkspaceManager extends Impersonable {
return new ItemList(toReturn);
}
/**
* Get a paged list of VRE folders for which the user is member
*
* @param start start index, counting from 0 <br>
* <strong>Possible values:</strong> integers
* @param limit maximum number of items returned <br>
* <strong>Possible values:</strong> integers
* @param exclude a list of fields to exclude from the returned item<br>
* <strong>Multivalued</strong><br>
* <strong>Optional</strong>
* @return list of VRE folders
* @pathExample /vrefolders/paged?start=0&limit=10
*/
@ResourceMethodSignature(output = ItemList.class, queryParams = { @QueryParam("start"), @QueryParam("limit"), @QueryParam("exclude") })
@Path("vrefolders/paged")
@GET
@Produces(MediaType.APPLICATION_JSON)
@ -566,13 +437,30 @@ public class WorkspaceManager extends Impersonable {
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); }
*/
// TODO: boh! Sviluppo a metà. Valutare se finirlo o ammazzarlo male
@Ignore
@StatusCodes({
@ResponseCode ( code = 200, condition = "List retrieved."),
@ResponseCode ( code = 406, condition = "Error retrieving shared-with-me folder."),
})
@Path("shared-with-me")
@GET
@Produces(MediaType.APPLICATION_JSON)
@ -601,7 +489,6 @@ public class WorkspaceManager extends Impersonable {
return new ItemList(toReturn);
}
@Ignore
@Path("count")
@GET
@Deprecated
@ -626,7 +513,6 @@ public class WorkspaceManager extends Impersonable {
return "0";
}
@Ignore
@Path("size")
@GET
@Deprecated

View File

@ -41,17 +41,12 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.webcohesion.enunciate.metadata.DocumentationExample;
import com.webcohesion.enunciate.metadata.rs.RequestHeader;
import com.webcohesion.enunciate.metadata.rs.RequestHeaders;
import com.webcohesion.enunciate.metadata.rs.ResourceMethodSignature;
import com.webcohesion.enunciate.metadata.rs.ResponseCode;
import com.webcohesion.enunciate.metadata.rs.StatusCodes;
import jakarta.inject.Inject;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.DefaultValue;
import jakarta.ws.rs.FormParam;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.Path;
@ -60,12 +55,9 @@ import jakarta.ws.rs.Produces;
import jakarta.ws.rs.WebApplicationException;
import jakarta.ws.rs.core.MediaType;
/**
* Manage "script" classes
*/
@Path("admin/script")
@RequestHeaders({
@RequestHeader( name = "Authorization", description = "Bearer token, see <a href=\"https://dev.d4science.org/how-to-access-resources\">https://dev.d4science.org/how-to-access-resources</a>"),
@RequestHeader( name = "Authorization", description = "Bearer token, see https://dev.d4science.org/how-to-access-resources"),
})
public class ScriptManager {
@ -92,62 +84,21 @@ public class ScriptManager {
protected static HashMap<String, ScriptStatus> scriptStatusMap = new HashMap<String, ScriptStatus>();
/**
* Execute a "script" class <br>
* <strong>Only users with <code>Infrastructure-Manager</code> role allowed</strong>
*
* @param name name of the script
* @param asynch if true, execute script asynchronously <br>
* <strong>Possible values:</strong> <code>true</code>, <code>false</code> <br>
* <strong>Optional</strong> default: <code>false</code>
* @param writeResult if true, write the result in the workspace <br>
* <strong>Possible values:</strong> <code>true</code>, <code>false</code> <br>
* <strong>Optional</strong> default: <code>false</code>
* @param destinationFolderId id of the destination folder
* @param file multipart/form-data file parameter, with optional
* 'filename' and 'size' (see example below)
* @return outcome of the script execution
*/
@ResourceMethodSignature(output = ScriptStatus.class, formParams = { @FormParam("name"),
@FormParam("asynch"), @FormParam("writeResult"), @FormParam("destinationFolderId"),
@FormParam("file") })
@DocumentationExample(value = "...\n\n--------boundaryString\n" +
"Content-Disposition: form-data; name=\"file\"; filename=\"MoveFiles.class\"; size=171018;\n" +
"Content-Type: application/octet-stream\n\n" +
"(binary data)\n" +
"--------boundaryString\n" +
"Content-Disposition: form-data; name=\"name\"\n\n" +
"MoveFile\n" +
"--------boundaryString\n" +
"Content-Disposition: form-data; name=\"async\"\n\n" +
"false\n" +
"--------boundaryString\n" +
"Content-Disposition: form-data; name=\"writeResult\"\n\n" +
"true\n" +
"--------boundaryString\n" +
"Content-Disposition: form-data; name=\"destinationFolderId=\"\n\n" +
"5f4b3b4e-4b3b- ... -4b3b4e4b3b4e\n" +
"--------boundaryString--")
@POST
@Path("execute")
@AuthorizationControl(allowedRoles = {INFRASTRUCTURE_MANAGER_ROLE})
@Consumes(MediaType.MULTIPART_FORM_DATA)
@Produces(MediaType.APPLICATION_JSON)
@StatusCodes({
@ResponseCode ( code = 200, condition = "Script correctly loaded."),
@ResponseCode ( code = 403, condition = "You're not allowed to run scripts."),
@ResponseCode ( code = 500, condition = "Error loading the script."),
})
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 file,
@FormDataParam("file") InputStream stream,
@FormDataParam("file") FormDataContentDisposition fileDetail) {
try {
InnerMethodName.set("executeScript");
ScriptClassLoader scriptClassLoader = new ScriptClassLoader(Thread.currentThread().getContextClassLoader());
Class<?> scriptClass = uploadClass(file, scriptClassLoader, fileDetail.getFileName().replace(".class", ""));
Class<?> scriptClass = uploadClass(stream, scriptClassLoader, fileDetail.getFileName().replace(".class", ""));
return internalRun(scriptClass, name, destinationFolderId, asynch, writeResult);
}catch(Throwable e) {
log.error("error executing script {}", name,e);
@ -155,19 +106,6 @@ public class ScriptManager {
}
}
/**
* Get the status of a script <br>
* <strong>Only users with <code>Infrastructure-Manager</code> role allowed</strong>
*
* @param id id of the script
* @return outcome of the script execution
*/
@ResourceMethodSignature(output = ScriptStatus.class, pathParams = { @PathParam("id") })
@StatusCodes({
@ResponseCode ( code = 200, condition = "Script status retrieved."),
@ResponseCode ( code = 403, condition = "You're not allowed to inquire script status."),
@ResponseCode ( code = 404, condition = "Script not found."),
})
@GET
@Path("{id}/status")
@AuthorizationControl(allowedRoles = {INFRASTRUCTURE_MANAGER_ROLE})
@ -185,17 +123,6 @@ public class ScriptManager {
}
/**
* Export the data <br>
* <strong>Only users with <code>Infrastructure-Manager</code> role allowed</strong>
*
* @return outcome of the export
*/
@StatusCodes({
@ResponseCode ( code = 200, condition = "Script status retrieved."),
@ResponseCode ( code = 403, condition = "You're not allowed to inquire script status."),
@ResponseCode ( code = 404, condition = "Script not found."),
})
@GET
@Path("export")
@AuthorizationControl(allowedRoles = {INFRASTRUCTURE_MANAGER_ROLE})