2018-12-04 12:06:22 +01:00
|
|
|
package org.gcube.gcat.rest;
|
|
|
|
|
2019-09-09 14:20:09 +02:00
|
|
|
import javax.ws.rs.BadRequestException;
|
2019-01-10 12:29:47 +01:00
|
|
|
import javax.ws.rs.Consumes;
|
|
|
|
import javax.ws.rs.DELETE;
|
2018-12-04 12:06:22 +01:00
|
|
|
import javax.ws.rs.DefaultValue;
|
|
|
|
import javax.ws.rs.GET;
|
|
|
|
import javax.ws.rs.HeaderParam;
|
2019-09-09 14:20:09 +02:00
|
|
|
import javax.ws.rs.HttpMethod;
|
2018-12-04 12:06:22 +01:00
|
|
|
import javax.ws.rs.InternalServerErrorException;
|
2019-09-06 16:55:46 +02:00
|
|
|
import javax.ws.rs.NotAllowedException;
|
2022-04-12 11:48:12 +02:00
|
|
|
//import javax.ws.rs.NotAuthorizedException;
|
2019-01-10 12:29:47 +01:00
|
|
|
import javax.ws.rs.PUT;
|
2018-12-04 12:06:22 +01:00
|
|
|
import javax.ws.rs.Path;
|
|
|
|
import javax.ws.rs.PathParam;
|
|
|
|
import javax.ws.rs.Produces;
|
2021-02-03 21:55:32 +01:00
|
|
|
import javax.ws.rs.QueryParam;
|
2019-05-20 17:23:49 +02:00
|
|
|
import javax.ws.rs.WebApplicationException;
|
2019-01-29 17:46:22 +01:00
|
|
|
import javax.ws.rs.core.Context;
|
2018-12-04 12:06:22 +01:00
|
|
|
import javax.ws.rs.core.MediaType;
|
2019-01-10 12:29:47 +01:00
|
|
|
import javax.ws.rs.core.Response;
|
2019-01-29 17:46:22 +01:00
|
|
|
import javax.ws.rs.core.Response.ResponseBuilder;
|
2019-01-10 12:29:47 +01:00
|
|
|
import javax.ws.rs.core.Response.Status;
|
2019-01-29 17:46:22 +01:00
|
|
|
import javax.ws.rs.core.UriInfo;
|
2018-12-04 12:06:22 +01:00
|
|
|
|
2022-02-21 10:34:52 +01:00
|
|
|
import org.gcube.com.fasterxml.jackson.databind.node.ArrayNode;
|
2022-04-12 11:48:12 +02:00
|
|
|
//import org.gcube.common.authorization.control.annotations.AuthorizationControl;
|
2019-09-06 16:38:15 +02:00
|
|
|
import org.gcube.datacatalogue.metadatadiscovery.DataCalogueMetadataFormatReader;
|
2021-02-03 21:55:32 +01:00
|
|
|
import org.gcube.gcat.api.GCatConstants;
|
2022-04-12 11:48:12 +02:00
|
|
|
//import org.gcube.gcat.api.roles.Role;
|
2019-02-27 13:02:20 +01:00
|
|
|
import org.gcube.gcat.profile.ISProfile;
|
2019-09-09 14:20:09 +02:00
|
|
|
import org.xml.sax.SAXException;
|
2018-12-04 12:06:22 +01:00
|
|
|
|
2022-09-28 16:58:17 +02:00
|
|
|
import com.webcohesion.enunciate.metadata.rs.ResourceGroup;
|
2022-09-28 14:45:02 +02:00
|
|
|
import com.webcohesion.enunciate.metadata.rs.ResourceLabel;
|
|
|
|
|
2018-12-04 12:06:22 +01:00
|
|
|
/**
|
2022-09-30 13:55:59 +02:00
|
|
|
* A Profile must comply with the defined <a href="../profiles/SCHEMA">XSD schema</a> .
|
2022-09-30 11:27:51 +02:00
|
|
|
*
|
2022-09-30 13:55:59 +02:00
|
|
|
* Please find the documentation of profile schema at:
|
|
|
|
* at <a href="https://wiki.gcube-system.org/gcube/GCat_Background#Metadata_Profile_v.4">Metadata Profile</>
|
2022-09-30 11:27:51 +02:00
|
|
|
*
|
2018-12-04 12:06:22 +01:00
|
|
|
* @author Luca Frosini (ISTI - CNR)
|
|
|
|
*/
|
2019-01-29 17:46:22 +01:00
|
|
|
@Path(Profile.PROFILES)
|
2022-09-28 16:58:17 +02:00
|
|
|
@ResourceGroup("Item Related APIs")
|
2022-09-28 14:45:02 +02:00
|
|
|
@ResourceLabel("Profile APIs")
|
2019-01-29 17:46:22 +01:00
|
|
|
public class Profile extends BaseREST implements org.gcube.gcat.api.interfaces.Profile<Response,Response> {
|
2018-12-04 12:06:22 +01:00
|
|
|
|
2019-01-10 12:29:47 +01:00
|
|
|
public static final String PROFILE_NAME_PARAMETER = "PROFILE_NAME";
|
2019-09-09 14:20:09 +02:00
|
|
|
public static final String PROFILE_VALIDATION_ERROR;
|
2018-12-04 12:06:22 +01:00
|
|
|
|
2019-09-09 14:25:27 +02:00
|
|
|
public static final String CANNOT_MANAGE_PROFILE_SCHEMA = "You cannot manage the profile schema";
|
|
|
|
|
2019-09-09 14:20:09 +02:00
|
|
|
static {
|
|
|
|
StringBuilder validationError = new StringBuilder();
|
|
|
|
validationError.append("The Profile is not valid because of the following error at validation time:\n%s\n\n");
|
|
|
|
validationError.append("The XSD used to validate the profile is available at %s\n\n");
|
|
|
|
validationError.append(
|
|
|
|
"To check your profile you can use a tool such as Oxygen XML Editor or an online service such as the one available at:\n");
|
|
|
|
validationError.append("- http://www.utilities-online.info/xsdvalidation/\n");
|
|
|
|
validationError.append("- https://www.freeformatter.com/xml-validator-xsd.html\n");
|
|
|
|
PROFILE_VALIDATION_ERROR = validationError.toString();
|
|
|
|
}
|
2019-09-06 16:38:15 +02:00
|
|
|
|
2019-01-29 17:46:22 +01:00
|
|
|
@Context
|
|
|
|
private UriInfo uriInfo;
|
|
|
|
|
2021-02-03 21:55:32 +01:00
|
|
|
/*
|
|
|
|
* Not used as REST method, implemented to respect {@link org.gcube.gcat.api.interfaces.Item} interface
|
|
|
|
*/
|
|
|
|
@Override
|
|
|
|
public int count() {
|
|
|
|
setCalledMethod("GET /" + PROFILES);
|
|
|
|
try {
|
|
|
|
ISProfile isProfile = new ISProfile();
|
|
|
|
return isProfile.count();
|
|
|
|
} catch(WebApplicationException e) {
|
|
|
|
throw e;
|
|
|
|
} catch(Exception e) {
|
|
|
|
throw new InternalServerErrorException(e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-09-30 13:55:59 +02:00
|
|
|
/**
|
|
|
|
* Returns the list of profiles name available for the
|
|
|
|
* context of the request
|
|
|
|
* (i.e. the context where the token has been generated).
|
|
|
|
*
|
|
|
|
* @param count (<em>Default:false</em>) If <code>count=true</code> the API returns total number of profile instead of the list.
|
|
|
|
* @return a JSON Array.
|
|
|
|
*
|
|
|
|
* @pathExample /profiles
|
|
|
|
* @responseExample application/json;charset=UTF-8 ["EmptyProfile","TestProfile",...,"ComplexProfile"]
|
|
|
|
*
|
|
|
|
* @pathExample /profiles?count=true
|
|
|
|
* @responseExample application/json;charset=UTF-8 {"count":5}
|
|
|
|
*
|
|
|
|
*/
|
2018-12-04 12:06:22 +01:00
|
|
|
@GET
|
2019-01-10 12:29:47 +01:00
|
|
|
@Produces(MediaType.APPLICATION_JSON)
|
2022-09-30 13:55:59 +02:00
|
|
|
public String listOrCount(@QueryParam(GCatConstants.COUNT_QUERY_PARAMETER) @DefaultValue("false") Boolean count) {
|
2019-01-29 17:46:22 +01:00
|
|
|
setCalledMethod("GET /" + PROFILES);
|
2021-02-03 21:55:32 +01:00
|
|
|
try {
|
|
|
|
ISProfile isProfile = new ISProfile();
|
2022-09-30 13:55:59 +02:00
|
|
|
if(count) {
|
2021-02-03 21:55:32 +01:00
|
|
|
return createCountJson(isProfile.count());
|
|
|
|
}else{
|
|
|
|
ArrayNode arrayNode = isProfile.list();
|
|
|
|
return isProfile.getMapper().writeValueAsString(arrayNode);
|
|
|
|
}
|
|
|
|
} catch(WebApplicationException e) {
|
|
|
|
throw e;
|
|
|
|
} catch(Exception e) {
|
|
|
|
throw new InternalServerErrorException(e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Not used as REST method, implemented to respect {@link org.gcube.gcat.api.interfaces.Item} interface
|
|
|
|
*/
|
|
|
|
@Override
|
|
|
|
public String list() {
|
2018-12-04 12:06:22 +01:00
|
|
|
try {
|
2019-02-27 13:02:20 +01:00
|
|
|
ISProfile isProfile = new ISProfile();
|
|
|
|
ArrayNode arrayNode = isProfile.list();
|
|
|
|
return isProfile.getMapper().writeValueAsString(arrayNode);
|
2019-05-20 17:23:49 +02:00
|
|
|
} catch(WebApplicationException e) {
|
2019-02-27 13:02:20 +01:00
|
|
|
throw e;
|
2018-12-04 12:06:22 +01:00
|
|
|
} catch(Exception e) {
|
2019-02-27 13:02:20 +01:00
|
|
|
throw new InternalServerErrorException(e);
|
2018-12-04 12:06:22 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public static int PRETTY_PRINT_INDENT_FACTOR = 4;
|
|
|
|
|
2022-09-30 13:55:59 +02:00
|
|
|
/**
|
|
|
|
* This API allow to read a profile definition.<br/>
|
|
|
|
*
|
|
|
|
* @param accept This API return by default the content in XML.
|
|
|
|
* <p>
|
|
|
|
* It is possible reading a profile in JSON by specifing the HTTP Header:<br/>
|
|
|
|
* <code>Accept: application/json</code>
|
|
|
|
* </p>
|
|
|
|
* @param name the name of the profile
|
|
|
|
* @return the profile definition
|
|
|
|
*
|
|
|
|
* @pathExample /profiles/EmptyProfile
|
|
|
|
* @requestExample application/json;charset=UTF-8
|
|
|
|
* @responseExample application/json;charset=UTF-8 classpath:/api-docs-examples/profile/read-profile-response.json
|
|
|
|
*
|
|
|
|
* @pathExample /profiles/EmptyProfile
|
|
|
|
* @requestExample application/xml
|
|
|
|
* @responseExample application/xml classpath:/api-docs-examples/profile/read-profile-response.xml
|
|
|
|
*
|
|
|
|
*/
|
2018-12-04 12:06:22 +01:00
|
|
|
@GET
|
|
|
|
@Path("/{" + PROFILE_NAME_PARAMETER + "}")
|
2022-09-30 13:55:59 +02:00
|
|
|
@Consumes({MediaType.APPLICATION_XML, GCatConstants.APPLICATION_JSON_CHARSET_UTF_8})
|
2022-02-21 10:34:52 +01:00
|
|
|
@Produces({MediaType.APPLICATION_XML, GCatConstants.APPLICATION_JSON_CHARSET_UTF_8})
|
2019-01-10 12:29:47 +01:00
|
|
|
public String read(@PathParam(PROFILE_NAME_PARAMETER) String name,
|
2019-01-29 17:46:22 +01:00
|
|
|
@DefaultValue(MediaType.APPLICATION_XML) @HeaderParam("Accept") String accept) {
|
|
|
|
setCalledMethod("GET /" + PROFILES + "/{" + PROFILE_NAME_PARAMETER + "}");
|
2018-12-04 12:06:22 +01:00
|
|
|
try {
|
2019-09-06 16:38:15 +02:00
|
|
|
// If the name is SCHEMA
|
2019-09-09 14:20:09 +02:00
|
|
|
if(name.compareToIgnoreCase(SCHEMA) == 0) {
|
2019-09-06 16:38:15 +02:00
|
|
|
return DataCalogueMetadataFormatReader.getProfileSchemaString();
|
|
|
|
}
|
|
|
|
|
2019-02-27 13:02:20 +01:00
|
|
|
ISProfile isProfile = new ISProfile();
|
2022-09-30 13:55:59 +02:00
|
|
|
boolean xml = true;
|
|
|
|
if(accept.startsWith(MediaType.APPLICATION_JSON)) {
|
|
|
|
xml = false;
|
2019-01-10 12:29:47 +01:00
|
|
|
}
|
2019-02-27 13:02:20 +01:00
|
|
|
return isProfile.read(name, xml);
|
2019-05-20 17:23:49 +02:00
|
|
|
} catch(WebApplicationException e) {
|
2019-01-10 12:29:47 +01:00
|
|
|
throw e;
|
|
|
|
} catch(Exception e) {
|
2019-02-27 13:02:20 +01:00
|
|
|
throw new InternalServerErrorException(e);
|
2019-01-10 12:29:47 +01:00
|
|
|
}
|
|
|
|
}
|
2019-05-20 17:23:49 +02:00
|
|
|
|
2019-01-10 12:29:47 +01:00
|
|
|
@PUT
|
|
|
|
@Path("/{" + PROFILE_NAME_PARAMETER + "}")
|
|
|
|
@Consumes(MediaType.APPLICATION_XML)
|
|
|
|
@Produces(MediaType.APPLICATION_XML)
|
2022-04-12 11:48:12 +02:00
|
|
|
// @AuthorizationControl(allowedRoles={Role.CATALOGUE_EDITOR, Role.CATALOGUE_ADMIN, Role.CATALOGUE_MANAGER}, exception=NotAuthorizedException.class)
|
2019-01-29 17:46:22 +01:00
|
|
|
public Response createOrUpdate(@PathParam(PROFILE_NAME_PARAMETER) String name, String xml) {
|
|
|
|
setCalledMethod("PUT /" + PROFILES + "/{" + PROFILE_NAME_PARAMETER + "}");
|
2019-01-10 12:29:47 +01:00
|
|
|
try {
|
2019-09-09 14:20:09 +02:00
|
|
|
if(name.compareToIgnoreCase(SCHEMA) == 0) {
|
2019-09-09 14:25:27 +02:00
|
|
|
throw new NotAllowedException(CANNOT_MANAGE_PROFILE_SCHEMA, new Throwable(CANNOT_MANAGE_PROFILE_SCHEMA),
|
2019-09-09 14:20:09 +02:00
|
|
|
HttpMethod.GET.toString(), HttpMethod.HEAD.toString());
|
2019-09-06 16:38:15 +02:00
|
|
|
}
|
2019-02-27 13:02:20 +01:00
|
|
|
ISProfile isProfile = new ISProfile();
|
|
|
|
boolean created = isProfile.createOrUpdate(name, xml);
|
|
|
|
ResponseBuilder responseBuilder = null;
|
|
|
|
if(created) {
|
|
|
|
responseBuilder = Response.status(Status.CREATED);
|
2019-01-29 17:46:22 +01:00
|
|
|
responseBuilder.header(LOCATION_HEADER, uriInfo.getAbsolutePath());
|
2019-05-20 17:23:49 +02:00
|
|
|
} else {
|
2019-02-27 13:02:20 +01:00
|
|
|
responseBuilder = Response.status(Status.OK);
|
2019-01-10 12:29:47 +01:00
|
|
|
}
|
2019-02-27 13:02:20 +01:00
|
|
|
responseBuilder.entity(xml);
|
|
|
|
return responseBuilder.type(MediaType.APPLICATION_XML).build();
|
2019-05-20 17:23:49 +02:00
|
|
|
} catch(WebApplicationException e) {
|
2019-01-10 12:29:47 +01:00
|
|
|
throw e;
|
2019-09-09 14:20:09 +02:00
|
|
|
} catch(SAXException e) {
|
|
|
|
String schemaURL = uriInfo.getRequestUri().toString().replace(name, SCHEMA);
|
|
|
|
throw new BadRequestException(String.format(PROFILE_VALIDATION_ERROR, e.getMessage(), schemaURL));
|
2019-01-10 12:29:47 +01:00
|
|
|
} catch(Exception e) {
|
2019-02-27 13:02:20 +01:00
|
|
|
throw new InternalServerErrorException(e);
|
2019-01-10 12:29:47 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@DELETE
|
|
|
|
@Path("/{" + PROFILE_NAME_PARAMETER + "}")
|
2022-04-12 11:48:12 +02:00
|
|
|
// @AuthorizationControl(allowedRoles={Role.CATALOGUE_EDITOR, Role.CATALOGUE_ADMIN, Role.CATALOGUE_MANAGER}, exception=NotAuthorizedException.class)
|
2019-01-10 12:29:47 +01:00
|
|
|
public Response delete(@PathParam(PROFILE_NAME_PARAMETER) String name) {
|
2019-01-29 17:46:22 +01:00
|
|
|
setCalledMethod("DELETE /" + PROFILES + "/{" + PROFILE_NAME_PARAMETER + "}");
|
2019-01-10 12:29:47 +01:00
|
|
|
try {
|
2019-09-09 14:20:09 +02:00
|
|
|
if(name.compareToIgnoreCase(SCHEMA) == 0) {
|
2019-09-09 14:25:27 +02:00
|
|
|
throw new NotAllowedException(CANNOT_MANAGE_PROFILE_SCHEMA, new Throwable(CANNOT_MANAGE_PROFILE_SCHEMA),
|
2019-09-09 14:20:09 +02:00
|
|
|
HttpMethod.GET.toString(), HttpMethod.HEAD.toString());
|
2019-09-06 16:38:15 +02:00
|
|
|
}
|
2019-02-27 13:02:20 +01:00
|
|
|
ISProfile isProfile = new ISProfile();
|
|
|
|
isProfile.delete(name);
|
|
|
|
return Response.status(Status.NO_CONTENT).build();
|
2019-05-20 17:23:49 +02:00
|
|
|
} catch(WebApplicationException e) {
|
2019-01-10 12:29:47 +01:00
|
|
|
throw e;
|
2018-12-04 12:06:22 +01:00
|
|
|
} catch(Exception e) {
|
2019-02-27 13:02:20 +01:00
|
|
|
throw new InternalServerErrorException(e);
|
2018-12-04 12:06:22 +01:00
|
|
|
}
|
|
|
|
}
|
2019-02-27 13:02:20 +01:00
|
|
|
|
2019-01-29 17:46:22 +01:00
|
|
|
@Override
|
|
|
|
public Response create(String name, String xml) {
|
|
|
|
return createOrUpdate(name, xml);
|
|
|
|
|
|
|
|
}
|
2018-12-04 12:06:22 +01:00
|
|
|
|
2019-01-29 17:46:22 +01:00
|
|
|
@Override
|
|
|
|
public String read(String name) {
|
|
|
|
return read(name, MediaType.APPLICATION_XML);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public String update(String name, String xml) {
|
|
|
|
return createOrUpdate(name, xml).getEntity().toString();
|
|
|
|
}
|
2021-02-03 21:55:32 +01:00
|
|
|
|
2018-12-04 12:06:22 +01:00
|
|
|
}
|