2018-12-04 12:06:22 +01:00
package org.gcube.gcat.persistence.ckan ;
import java.io.IOException ;
2021-03-15 10:02:38 +01:00
import java.io.InputStream ;
2019-01-10 12:29:47 +01:00
import java.io.UnsupportedEncodingException ;
import java.net.HttpURLConnection ;
2018-12-04 12:06:22 +01:00
import java.util.HashMap ;
import java.util.Map ;
import javax.ws.rs.BadRequestException ;
2019-09-18 12:57:30 +02:00
import javax.ws.rs.ForbiddenException ;
2018-12-04 12:06:22 +01:00
import javax.ws.rs.InternalServerErrorException ;
import javax.ws.rs.NotFoundException ;
import javax.ws.rs.WebApplicationException ;
2019-05-20 17:23:49 +02:00
import javax.ws.rs.core.HttpHeaders ;
2021-03-15 10:02:38 +01:00
import javax.ws.rs.core.Response.Status ;
2019-05-20 17:23:49 +02:00
import javax.ws.rs.core.UriInfo ;
2018-12-04 12:06:22 +01:00
2020-12-01 16:58:36 +01:00
import org.gcube.com.fasterxml.jackson.core.JsonProcessingException ;
import org.gcube.com.fasterxml.jackson.databind.JsonNode ;
import org.gcube.com.fasterxml.jackson.databind.ObjectMapper ;
import org.gcube.com.fasterxml.jackson.databind.node.NullNode ;
import org.gcube.com.fasterxml.jackson.databind.node.ObjectNode ;
2021-03-15 10:02:38 +01:00
import org.gcube.common.gxhttp.request.GXHTTPStringRequest ;
2022-02-16 22:34:30 +01:00
import org.gcube.gcat.configuration.CatalogueConfigurationFactory ;
2021-03-15 10:02:38 +01:00
import org.gcube.gcat.utils.HTTPUtility ;
import org.slf4j.Logger ;
import org.slf4j.LoggerFactory ;
2018-12-04 12:06:22 +01:00
/ * *
* @author Luca Frosini ( ISTI - CNR )
* /
public abstract class CKAN {
private static final Logger logger = LoggerFactory . getLogger ( CKAN . class ) ;
protected static final String ID_KEY = " id " ;
2022-04-06 17:15:46 +02:00
protected static final String TITLE_KEY = " title " ;
2018-12-04 12:06:22 +01:00
protected static final String NAME_KEY = " name " ;
protected static final String ERROR_KEY = " error " ;
protected static final String ERROR_TYPE_KEY = " __type " ;
protected static final String MESSAGE_KEY = " message " ;
protected static final String OWNER_ORG_KEY = " owner_org " ;
protected static final String RESULT_KEY = " result " ;
protected static final String SUCCESS_KEY = " success " ;
2019-01-10 12:29:47 +01:00
public static final String LIMIT_KEY = " limit " ;
public static final String OFFSET_KEY = " offset " ;
2018-12-04 12:06:22 +01:00
protected static final String NOT_FOUND_ERROR = " Not Found Error " ;
protected static final String AUTHORIZATION_ERROR = " Authorization Error " ;
protected static final String VALIDATION_ERROR = " Validation Error " ;
// api rest path CKAN
public final static String CKAN_API_PATH = " /api/3/action/ " ;
// ckan header authorization
2019-05-20 17:23:49 +02:00
public final static String AUTH_CKAN_HEADER = HttpHeaders . AUTHORIZATION ;
2018-12-04 12:06:22 +01:00
2019-01-10 12:29:47 +01:00
public final static String NAME_REGEX = " ^[a-z0-9_ \\ \\ -]{2,100}$ " ;
2018-12-04 12:06:22 +01:00
protected String LIST ;
protected String CREATE ;
protected String READ ;
protected String UPDATE ;
protected String PATCH ;
protected String DELETE ;
protected String PURGE ;
protected final ObjectMapper mapper ;
protected String name ;
protected String apiKey ;
protected JsonNode result ;
2019-01-10 12:29:47 +01:00
protected String nameRegex ;
2018-12-04 12:06:22 +01:00
2019-05-20 17:23:49 +02:00
protected UriInfo uriInfo ;
public void setUriInfo ( UriInfo uriInfo ) {
this . uriInfo = uriInfo ;
}
2019-09-16 14:48:18 +02:00
2018-12-04 12:06:22 +01:00
public String getApiKey ( ) {
2019-01-10 12:29:47 +01:00
if ( apiKey = = null ) {
2018-12-04 12:06:22 +01:00
try {
return CKANUtility . getApiKey ( ) ;
2019-01-10 12:29:47 +01:00
} catch ( Exception e ) {
2018-12-04 12:06:22 +01:00
throw new InternalServerErrorException ( e ) ;
}
}
return apiKey ;
}
2019-01-10 12:29:47 +01:00
2018-12-04 12:06:22 +01:00
public void setApiKey ( String apiKey ) {
this . apiKey = apiKey ;
}
2019-01-10 12:29:47 +01:00
2018-12-04 12:06:22 +01:00
public String getName ( ) {
return name ;
}
public void setName ( String name ) {
this . name = name ;
}
public ObjectMapper getMapper ( ) {
return mapper ;
}
public JsonNode getJsonNodeResult ( ) {
return result ;
}
protected CKAN ( ) {
try {
this . mapper = new ObjectMapper ( ) ;
2019-01-10 12:29:47 +01:00
this . nameRegex = CKAN . NAME_REGEX ;
} catch ( Exception e ) {
2018-12-04 12:06:22 +01:00
throw new InternalServerErrorException ( e ) ;
}
}
protected JsonNode getAsJsonNode ( String json ) {
try {
return mapper . readTree ( json ) ;
} catch ( IOException e ) {
throw new BadRequestException ( e ) ;
}
}
2021-03-15 10:02:38 +01:00
2018-12-04 12:06:22 +01:00
/ * *
* Validate the CKAN response and return the
* @param json
2019-10-04 17:04:50 +02:00
* @return the validated response as JsonNode
2018-12-04 12:06:22 +01:00
* /
protected JsonNode validateCKANResponse ( String json ) {
JsonNode jsonNode = getAsJsonNode ( json ) ;
if ( jsonNode . get ( SUCCESS_KEY ) . asBoolean ( ) ) {
return jsonNode . get ( RESULT_KEY ) ;
} else {
try {
JsonNode error = jsonNode . get ( ERROR_KEY ) ;
String errorType = error . get ( ERROR_TYPE_KEY ) . asText ( ) ;
if ( errorType . compareTo ( VALIDATION_ERROR ) = = 0 ) {
throw new BadRequestException ( getAsString ( error ) ) ;
}
String message = error . get ( MESSAGE_KEY ) . asText ( ) ;
if ( errorType . compareTo ( NOT_FOUND_ERROR ) = = 0 ) {
throw new NotFoundException ( message ) ;
}
if ( errorType . compareTo ( AUTHORIZATION_ERROR ) = = 0 ) {
2019-09-18 12:57:30 +02:00
throw new ForbiddenException ( message ) ;
2018-12-04 12:06:22 +01:00
}
// TODO parse more cases
} catch ( WebApplicationException e ) {
throw e ;
} catch ( Exception e ) {
throw new BadRequestException ( json ) ;
}
throw new BadRequestException ( json ) ;
}
}
protected String getAsString ( JsonNode node ) {
try {
String json = mapper . writeValueAsString ( node ) ;
return json ;
} catch ( JsonProcessingException e ) {
throw new InternalServerErrorException ( e ) ;
}
}
protected JsonNode checkName ( JsonNode jsonNode ) {
try {
String gotName = jsonNode . get ( NAME_KEY ) . asText ( ) ;
2019-01-10 12:29:47 +01:00
if ( ! gotName . matches ( nameRegex ) ) {
2019-09-16 14:48:18 +02:00
throw new BadRequestException (
" The 'name' must be between 2 and 100 characters long and contain only lowercase alphanumeric characters, '-' and '_'. You can validate your name using the regular expression : "
+ NAME_REGEX ) ;
2019-01-10 12:29:47 +01:00
}
if ( name = = null ) {
2018-12-04 12:06:22 +01:00
name = gotName ;
}
if ( gotName ! = null & & gotName . compareTo ( name ) ! = 0 ) {
String error = String . format (
2019-01-10 12:29:47 +01:00
" The name (%s) does not match with the '%s' contained in the provided content (%s). " , name ,
NAME_KEY , gotName ) ;
2018-12-04 12:06:22 +01:00
throw new BadRequestException ( error ) ;
}
return jsonNode ;
} catch ( BadRequestException e ) {
throw e ;
} catch ( Exception e ) {
throw new BadRequestException ( " Unable to obtain a correct 'name' from the provided content " ) ;
}
}
protected JsonNode checkName ( String json ) {
JsonNode jsonNode = getAsJsonNode ( json ) ;
checkName ( jsonNode ) ;
return jsonNode ;
}
protected JsonNode createJsonNodeWithID ( String id ) {
ObjectNode objectNode = mapper . createObjectNode ( ) ;
objectNode . put ( ID_KEY , id ) ;
return objectNode ;
}
protected JsonNode createJsonNodeWithNameAsID ( ) {
return createJsonNodeWithID ( name ) ;
}
protected Map < String , String > getMapWithNameAsID ( ) {
return getMapWithID ( name ) ;
}
protected Map < String , String > getMapWithID ( String id ) {
Map < String , String > map = new HashMap < > ( ) ;
map . put ( ID_KEY , id ) ;
return map ;
}
2019-09-16 14:48:18 +02:00
protected GXHTTPStringRequest getGXHTTPStringRequest ( String path , boolean post )
throws UnsupportedEncodingException {
2022-02-15 09:59:02 +01:00
String catalogueURL = CatalogueConfigurationFactory . getInstance ( ) . getCkanURL ( ) ;
2019-05-20 17:23:49 +02:00
2019-09-12 14:26:24 +02:00
GXHTTPStringRequest gxhttpStringRequest = HTTPUtility . createGXHTTPStringRequest ( catalogueURL , path , post ) ;
2019-01-10 12:29:47 +01:00
gxhttpStringRequest . isExternalCall ( true ) ;
gxhttpStringRequest . header ( AUTH_CKAN_HEADER , getApiKey ( ) ) ;
2019-09-12 14:26:24 +02:00
2019-01-10 12:29:47 +01:00
return gxhttpStringRequest ;
2018-12-04 12:06:22 +01:00
}
2021-03-15 10:02:38 +01:00
protected String getResultAsString ( HttpURLConnection httpURLConnection ) throws IOException {
int responseCode = httpURLConnection . getResponseCode ( ) ;
if ( responseCode > = Status . BAD_REQUEST . getStatusCode ( ) ) {
Status status = Status . fromStatusCode ( responseCode ) ;
2021-11-23 17:53:37 +01:00
switch ( status ) {
case NOT_FOUND :
throw new NotFoundException ( ) ;
default :
break ;
}
2021-03-15 10:02:38 +01:00
InputStream inputStream = httpURLConnection . getErrorStream ( ) ;
StringBuilder result = HTTPUtility . getStringBuilder ( inputStream ) ;
logger . trace ( result . toString ( ) ) ;
try {
JsonNode jsonNode = getAsJsonNode ( result . toString ( ) ) ;
JsonNode error = jsonNode . get ( ERROR_KEY ) ;
throw new WebApplicationException ( getAsString ( error ) , status ) ;
} catch ( WebApplicationException e ) {
throw e ;
} catch ( Exception e ) {
throw new WebApplicationException ( result . toString ( ) , status ) ;
}
}
InputStream inputStream = httpURLConnection . getInputStream ( ) ;
String ret = HTTPUtility . getStringBuilder ( inputStream ) . toString ( ) ;
logger . trace ( " Got Respose is {} " , ret ) ;
return ret ;
}
2019-09-12 14:26:24 +02:00
protected String getResultAndValidate ( HttpURLConnection httpURLConnection ) throws IOException {
2021-03-15 10:02:38 +01:00
String ret = getResultAsString ( httpURLConnection ) ;
2019-01-10 12:29:47 +01:00
logger . trace ( " Got Respose is {} " , ret ) ;
result = validateCKANResponse ( ret ) ;
if ( result instanceof NullNode ) {
result = mapper . createObjectNode ( ) ;
}
2018-12-04 12:06:22 +01:00
return getAsString ( result ) ;
}
2019-01-10 12:29:47 +01:00
protected String sendGetRequest ( String path , Map < String , String > parameters ) {
try {
2019-02-08 15:31:29 +01:00
logger . debug ( " Going to send GET request with parameters {} " , parameters ) ;
2019-05-20 17:23:49 +02:00
GXHTTPStringRequest gxhttpStringRequest = getGXHTTPStringRequest ( path , false ) ;
2019-01-10 12:29:47 +01:00
gxhttpStringRequest . queryParams ( parameters ) ;
HttpURLConnection httpURLConnection = gxhttpStringRequest . get ( ) ;
2019-09-12 14:26:24 +02:00
return getResultAndValidate ( httpURLConnection ) ;
2019-01-10 12:29:47 +01:00
} catch ( WebApplicationException e ) {
throw e ;
} catch ( Exception e ) {
throw new InternalServerErrorException ( e ) ;
}
}
protected String sendPostRequest ( String path , String body ) {
try {
2019-02-08 15:31:29 +01:00
logger . debug ( " Going to send POST request with body {} " , body ) ;
2019-05-20 17:23:49 +02:00
GXHTTPStringRequest gxhttpStringRequest = getGXHTTPStringRequest ( path , true ) ;
2019-01-10 12:29:47 +01:00
HttpURLConnection httpURLConnection = gxhttpStringRequest . post ( body ) ;
2019-09-12 14:26:24 +02:00
return getResultAndValidate ( httpURLConnection ) ;
2019-01-10 12:29:47 +01:00
} catch ( WebApplicationException e ) {
throw e ;
} catch ( Exception e ) {
throw new InternalServerErrorException ( e ) ;
}
}
protected String sendPostRequest ( String path , JsonNode jsonNode ) {
2018-12-04 12:06:22 +01:00
return sendPostRequest ( path , getAsString ( jsonNode ) ) ;
}
2019-01-10 12:29:47 +01:00
public String list ( int limit , int offset ) {
Map < String , String > parameters = new HashMap < > ( ) ;
if ( limit > 0 ) {
parameters . put ( LIMIT_KEY , String . valueOf ( limit ) ) ;
}
if ( offset > = 0 ) {
parameters . put ( OFFSET_KEY , String . valueOf ( offset ) ) ;
}
return sendGetRequest ( LIST , parameters ) ;
2018-12-04 12:06:22 +01:00
}
public String create ( String json ) {
return sendPostRequest ( CREATE , json ) ;
}
public String read ( ) {
return sendGetRequest ( READ , getMapWithNameAsID ( ) ) ;
}
public String update ( String json ) {
checkName ( json ) ;
return sendPostRequest ( UPDATE , json ) ;
}
public String patch ( String json ) {
JsonNode jsonNode = checkName ( json ) ;
ObjectNode objectNode = ( ( ObjectNode ) jsonNode ) ;
objectNode . put ( ID_KEY , name ) ;
objectNode . remove ( NAME_KEY ) ;
return sendPostRequest ( PATCH , objectNode ) ;
}
protected void delete ( ) {
sendPostRequest ( DELETE , createJsonNodeWithNameAsID ( ) ) ;
}
public void delete ( boolean purge ) {
if ( purge ) {
purge ( ) ;
} else {
delete ( ) ;
}
}
protected void purge ( ) {
sendPostRequest ( PURGE , createJsonNodeWithNameAsID ( ) ) ;
}
}