2018-12-05 16:58:44 +01:00
/ * *
*
* /
package org.gcube.datatransfer.resolver.services ;
2018-12-17 15:12:59 +01:00
import static org.gcube.common.authorization.client.Constants.authorizationService ;
import static org.gcube.resources.discovery.icclient.ICFactory.clientFor ;
import static org.gcube.resources.discovery.icclient.ICFactory.queryFor ;
2018-12-05 16:58:44 +01:00
import java.io.ByteArrayOutputStream ;
import java.io.File ;
2018-12-12 15:38:44 +01:00
import java.io.FileInputStream ;
2018-12-05 16:58:44 +01:00
import java.io.IOException ;
2018-12-12 15:38:44 +01:00
import java.net.URL ;
2018-12-05 16:58:44 +01:00
import java.nio.file.Files ;
2018-12-17 15:12:59 +01:00
import java.util.Collection ;
import java.util.HashMap ;
import java.util.List ;
import java.util.Map ;
2018-12-05 16:58:44 +01:00
import javax.servlet.http.HttpServletRequest ;
import javax.ws.rs.Consumes ;
import javax.ws.rs.POST ;
import javax.ws.rs.Path ;
import javax.ws.rs.Produces ;
2018-12-14 11:53:50 +01:00
import javax.ws.rs.WebApplicationException ;
2018-12-05 16:58:44 +01:00
import javax.ws.rs.core.Context ;
import javax.ws.rs.core.MediaType ;
import javax.ws.rs.core.Response ;
import javax.xml.bind.JAXBException ;
2018-12-12 15:38:44 +01:00
import org.apache.commons.io.IOUtils ;
2018-12-17 15:12:59 +01:00
import org.gcube.common.authorization.library.AuthorizationEntry ;
import org.gcube.common.authorization.library.provider.ClientInfo ;
2018-12-07 10:41:18 +01:00
import org.gcube.common.authorization.library.provider.SecurityTokenProvider ;
2018-12-17 15:12:59 +01:00
import org.gcube.common.encryption.StringEncrypter ;
import org.gcube.common.resources.gcore.ServiceEndpoint ;
import org.gcube.common.resources.gcore.ServiceEndpoint.AccessPoint ;
import org.gcube.common.resources.gcore.ServiceEndpoint.Property ;
2018-12-05 16:58:44 +01:00
import org.gcube.common.scope.api.ScopeProvider ;
import org.gcube.common.scope.impl.ScopeBean ;
import org.gcube.common.scope.impl.ScopeBean.Type ;
2018-12-17 15:12:59 +01:00
import org.gcube.common.storagehub.model.Metadata ;
2018-12-05 16:58:44 +01:00
import org.gcube.data.analysis.dminvocation.ActionType ;
import org.gcube.data.analysis.dminvocation.DataMinerInvocationManager ;
import org.gcube.data.analysis.dminvocation.model.DataMinerInvocation ;
2018-12-07 10:41:18 +01:00
import org.gcube.datatransfer.resolver.requesthandler.TokenSetter ;
2018-12-05 16:58:44 +01:00
import org.gcube.datatransfer.resolver.services.error.ExceptionManager ;
2018-12-17 15:12:59 +01:00
import org.gcube.datatransfer.resolver.util.ScopeUtil ;
2018-12-05 16:58:44 +01:00
import org.gcube.datatransfer.resolver.util.Util ;
2018-12-17 15:12:59 +01:00
import org.gcube.resources.discovery.client.api.DiscoveryClient ;
import org.gcube.resources.discovery.client.queries.api.SimpleQuery ;
import org.gcube.storagehub.ApplicationMode ;
import org.gcube.storagehub.StorageHubManagement ;
2018-12-05 16:58:44 +01:00
import org.slf4j.Logger ;
import org.slf4j.LoggerFactory ;
2018-12-12 15:38:44 +01:00
import org.xml.sax.SAXException ;
2018-12-05 16:58:44 +01:00
/ * *
2018-12-12 15:38:44 +01:00
* The Class AnalyticsCreateResolver .
2018-12-05 16:58:44 +01:00
*
2018-12-12 15:38:44 +01:00
* @author Francesco Mangiacrapa at ISTI - CNR ( francesco . mangiacrapa @isti.cnr.it )
* Dec 12 , 2018
2018-12-05 16:58:44 +01:00
* /
@Path ( " /analytics " )
public class AnalyticsCreateResolver {
2018-12-17 15:12:59 +01:00
/ * *
*
* /
protected static final String GCUBE_TOKEN = " gcube-token " ;
/ * *
*
* /
private static final String ANALYTICS_RESOLVER_SERVICE_ENDPOINT_NAME = " Analytics-Resolver " ;
2018-12-07 10:41:18 +01:00
private static final String DATAMINER_INVOCATION_MODEL = " dim " ;
2018-12-05 16:58:44 +01:00
private static Logger logger = LoggerFactory . getLogger ( AnalyticsCreateResolver . class ) ;
2018-12-13 12:39:55 +01:00
private static String helpURI = " https://gcube.wiki.gcube-system.org/gcube/URI_Resolver#Analytics_Resolver " ;
2018-12-05 16:58:44 +01:00
2018-12-13 11:09:08 +01:00
2018-12-05 16:58:44 +01:00
/ * *
2018-12-13 11:09:08 +01:00
* Creates the analytics url .
2018-12-05 16:58:44 +01:00
*
* @param req the req
2018-12-12 15:38:44 +01:00
* @param body the body
2018-12-05 16:58:44 +01:00
* @return the response
2018-12-17 15:12:59 +01:00
* @throws WebApplicationException the web application exception
2018-12-05 16:58:44 +01:00
* /
@POST
@Path ( " /create " )
2018-12-12 15:38:44 +01:00
@Consumes ( MediaType . TEXT_PLAIN )
2018-12-05 16:58:44 +01:00
@Produces ( MediaType . TEXT_PLAIN )
2018-12-14 11:53:50 +01:00
public Response createAnalyticsURL ( @Context HttpServletRequest req , String body ) throws WebApplicationException {
2018-12-05 16:58:44 +01:00
logger . info ( this . getClass ( ) . getSimpleName ( ) + " POST starts... " ) ;
2018-12-14 11:53:50 +01:00
try {
logger . info ( " body is: " + body ) ;
2018-12-07 10:41:18 +01:00
2018-12-14 11:53:50 +01:00
DataMinerInvocation jsonRequest = null ;
try {
2018-12-07 10:41:18 +01:00
2018-12-14 11:53:50 +01:00
jsonRequest = DataMinerInvocationManager . getInstance ( ) . unmarshaling ( IOUtils . toInputStream ( body ) , org . gcube . data . analysis . dminvocation . MediaType . ApplicationJSON , true ) ;
}
catch ( IOException | JAXBException | SAXException e1 ) {
logger . error ( " The body is not a valid DataMinerInvocation JSON request " , e1 ) ;
throw ExceptionManager . badRequestException ( req , " Bad 'dataminer-invocation' JSON request: \ n " + e1 . getCause ( ) . getMessage ( ) , this . getClass ( ) , helpURI ) ;
}
2018-12-07 10:41:18 +01:00
2018-12-14 11:53:50 +01:00
logger . debug ( " The body contains the request: " + jsonRequest . toString ( ) ) ;
2018-12-07 10:41:18 +01:00
2018-12-14 11:53:50 +01:00
String contextToken = SecurityTokenProvider . instance . get ( ) ;
String scope = ScopeProvider . instance . get ( ) ;
// logger.info("SecurityTokenProvider contextToken: "+contextToken);
logger . info ( " ScopeProvider has scope: " + scope ) ;
2018-12-07 10:41:18 +01:00
2018-12-14 11:53:50 +01:00
String appToken = req . getServletContext ( ) . getInitParameter ( TokenSetter . ROOT_APP_TOKEN ) ;
2018-12-07 10:41:18 +01:00
2018-12-14 11:53:50 +01:00
if ( contextToken . compareTo ( appToken ) = = 0 ) {
logger . error ( " Token not passed, SecurityTokenProvider contains the root app token: " + appToken . substring ( 0 , 10 ) + " ... " ) ;
throw ExceptionManager . unauthorizedException ( req , " You are not authorized. You must pass a token of VRE " , this . getClass ( ) , helpURI ) ;
}
2018-12-05 16:58:44 +01:00
2018-12-14 11:53:50 +01:00
String operatorID = jsonRequest . getOperatorId ( ) ;
2018-12-05 16:58:44 +01:00
2018-12-14 11:53:50 +01:00
if ( scope = = null | | scope . isEmpty ( ) ) {
logger . error ( " The parameter 'scope' not found or empty in the JSON object " ) ;
throw ExceptionManager . badRequestException ( req , " Mandatory body parameter 'scope' not found or empty in the JSON object " , this . getClass ( ) , helpURI ) ;
}
2018-12-05 16:58:44 +01:00
2018-12-14 11:53:50 +01:00
if ( operatorID = = null | | operatorID . isEmpty ( ) ) {
logger . error ( " The parameter 'operatorId' not found or empty in the JSON object " ) ;
throw ExceptionManager . badRequestException ( req , " Mandatory body parameter 'operatorId' not found or empty in the JSON object " , this . getClass ( ) , helpURI ) ;
}
ScopeBean scopeBean = new ScopeBean ( scope ) ;
String publicLinkToDMInvFile = " " ;
2018-12-05 16:58:44 +01:00
2018-12-14 11:53:50 +01:00
if ( scopeBean . is ( Type . VRE ) ) {
String vreName = scopeBean . name ( ) ;
2018-12-05 16:58:44 +01:00
2018-12-14 11:53:50 +01:00
String analyticsGetResolverURL = String . format ( " %s/%s " , Util . getServerURL ( req ) , " analytics/get " ) ;
//Creating DM invocation file
if ( jsonRequest . getActionType ( ) = = null )
jsonRequest . setActionType ( ActionType . RUN ) ;
2018-12-13 11:09:08 +01:00
2018-12-14 11:53:50 +01:00
File tempInvocationFile = null ;
try {
2018-12-13 11:09:08 +01:00
2018-12-14 11:53:50 +01:00
ByteArrayOutputStream xmlByteArray = DataMinerInvocationManager . getInstance ( ) . marshaling ( jsonRequest , org . gcube . data . analysis . dminvocation . MediaType . ApplicationXML , true ) ;
String uniqueName = createDMInvocationFileName ( jsonRequest . getOperatorId ( ) ) ;
tempInvocationFile = createTempFile ( uniqueName , " .xml " , xmlByteArray . toByteArray ( ) ) ;
logger . info ( " Created StorageHubClient Instance, uploading file: " + tempInvocationFile . getName ( ) ) ;
2018-12-17 15:12:59 +01:00
2018-12-17 15:18:20 +01:00
String infra = ScopeUtil . getInfrastructureNameFromScope ( ScopeProvider . instance . get ( ) ) ;
2018-12-17 15:12:59 +01:00
String theAppToken = readApplicationTokenFromSE ( req , infra ) ;
ApplicationMode applicationMode = new ApplicationMode ( theAppToken ) ;
applicationMode . start ( ) ;
StorageHubManagement storageHubManagement = new StorageHubManagement ( ) ;
Metadata metadata = new Metadata ( ) ;
Map < String , String > theMap = new HashMap < String , String > ( ) ;
AuthorizationEntry entry = authorizationService ( ) . get ( contextToken ) ;
//retrieve the info of the token owner
ClientInfo clientInfo = entry . getClientInfo ( ) ;
String owner = clientInfo . getId ( ) ; //IS THIS THE USERNAME?
theMap . put ( " owner " , owner ) ;
logger . info ( " Saving dataminer-invocation file for the user: " + owner ) ;
URL thePublicLink = storageHubManagement . persistFile ( new FileInputStream ( tempInvocationFile ) , tempInvocationFile . getName ( ) , " application/xml " , metadata ) ;
logger . info ( " Saved dataminer-invocation file at: " + thePublicLink ) ;
// FileContainer fileContainer = shc.getWSRoot().uploadFile(new FileInputStream(tempInvocationFile), tempInvocationFile.getName(), "DataMinerInvocation Request created by "+this.getClass().getSimpleName());
// logger.info("UPLOADED FILE at: "+fileContainer.getPublicLink());
// URL thePublicLink = fileContainer.getPublicLink();
2018-12-14 11:53:50 +01:00
publicLinkToDMInvFile = thePublicLink ! = null ? thePublicLink . toString ( ) : null ;
}
catch ( Exception e ) {
logger . error ( " Error on creating 'dataminer-invocation: " , e ) ;
throw ExceptionManager . badRequestException ( req , " Error on creating your 'dataminer-invocation' request with " + jsonRequest + " . \ nPlease contact the support " , this . getClass ( ) , helpURI ) ;
} finally {
try {
//DELETING THE TEMP FILE
if ( tempInvocationFile ! = null & & tempInvocationFile . exists ( ) )
tempInvocationFile . delete ( ) ;
} catch ( Exception e ) {
//silent
}
2018-12-12 15:38:44 +01:00
}
2018-12-05 16:58:44 +01:00
2018-12-14 11:53:50 +01:00
if ( publicLinkToDMInvFile = = null ) {
logger . error ( " Error on creating the public link to file " ) ;
throw ExceptionManager . badRequestException ( req , " Error on getting link to your 'dataminer-invocation' request. Plese contact the support " + jsonRequest , this . getClass ( ) , helpURI ) ;
}
String dataMinerURL = String . format ( " %s/%s?%s=%s " , analyticsGetResolverURL , vreName , DATAMINER_INVOCATION_MODEL , publicLinkToDMInvFile ) ;
logger . info ( " Returning Analytics URL: " + dataMinerURL ) ;
return Response . ok ( dataMinerURL ) . header ( " Location " , dataMinerURL ) . build ( ) ;
} else {
logger . error ( " The input scope " + scope + " is not a VRE " ) ;
throw ExceptionManager . badRequestException ( req , " Working in the " + scope + " scope that is not a VRE. Use a token of VRE " , this . getClass ( ) , helpURI ) ;
2018-12-13 11:09:08 +01:00
}
2018-12-05 16:58:44 +01:00
2018-12-14 11:53:50 +01:00
} catch ( Exception e ) {
2018-12-05 16:58:44 +01:00
2018-12-14 11:53:50 +01:00
if ( ! ( e instanceof WebApplicationException ) ) {
//UNEXPECTED EXCEPTION managing it as WebApplicationException
2018-12-14 14:26:37 +01:00
String error = " Error occurred on creating the Analytics for the request " + body + " . Please, contact the support! " ;
if ( e . getCause ( ) ! = null )
error + = " \ n \ nCaused: " + e . getCause ( ) . getMessage ( ) ;
2018-12-14 11:53:50 +01:00
throw ExceptionManager . internalErrorException ( req , error , this . getClass ( ) , helpURI ) ;
}
//ALREADY MANAGED AS WebApplicationException
logger . error ( " Exception: " , e ) ;
throw ( WebApplicationException ) e ;
2018-12-05 16:58:44 +01:00
}
}
2018-12-17 15:12:59 +01:00
/ * *
* Reads the Application Token from Service Endpoint { @link AnalyticsCreateResolver # ANALYTICS_RESOLVER_SERVICE_ENDPOINT_NAME }
*
* @param req the req
* @param scope the scope
* @return the string
* /
private static String readApplicationTokenFromSE ( HttpServletRequest req , String scope ) {
String origalScope = null ;
String gCubeAppToken = null ;
try {
origalScope = ScopeProvider . instance . get ( ) ;
ScopeProvider . instance . set ( scope ) ;
logger . info ( " Searching SE " + ANALYTICS_RESOLVER_SERVICE_ENDPOINT_NAME + " configurations in the scope: " + ScopeProvider . instance . get ( ) ) ;
SimpleQuery query = queryFor ( ServiceEndpoint . class ) ;
query . addCondition ( " $resource/Profile/Name/text() eq ' " + ANALYTICS_RESOLVER_SERVICE_ENDPOINT_NAME + " ' " ) ;
query . addCondition ( " $resource/Profile/Category/text() eq 'Service' " ) ;
DiscoveryClient < ServiceEndpoint > client = clientFor ( ServiceEndpoint . class ) ;
List < ServiceEndpoint > toReturn = client . submit ( query ) ;
logger . info ( " The query returned " + toReturn . size ( ) + " ServiceEndpoint/s " ) ;
if ( toReturn . size ( ) = = 0 ) {
String errorMessage = " No " + ANALYTICS_RESOLVER_SERVICE_ENDPOINT_NAME + " registered in the scope: " + ScopeProvider . instance . get ( ) ;
logger . error ( errorMessage ) ;
throw ExceptionManager . internalErrorException ( req , errorMessage , AnalyticsCreateResolver . class , helpURI ) ;
}
ServiceEndpoint se = toReturn . get ( 0 ) ;
Collection < AccessPoint > theAccessPoints = se . profile ( ) . accessPoints ( ) . asCollection ( ) ;
for ( AccessPoint accessPoint : theAccessPoints ) {
Collection < Property > properties = accessPoint . properties ( ) . asCollection ( ) ;
for ( Property property : properties ) {
if ( property . name ( ) . equalsIgnoreCase ( GCUBE_TOKEN ) ) {
logger . info ( " gcube-token as property was found, returning it " ) ;
gCubeAppToken = property . value ( ) ;
break ;
}
}
if ( gCubeAppToken ! = null )
break ;
}
if ( gCubeAppToken ! = null ) {
String decryptedPassword = StringEncrypter . getEncrypter ( ) . decrypt ( gCubeAppToken ) ;
logger . info ( " Returning decrypted Application Token registered into " + ANALYTICS_RESOLVER_SERVICE_ENDPOINT_NAME + " : " + decryptedPassword . substring ( 0 , decryptedPassword . length ( ) / 2 ) + " .... " ) ;
return gCubeAppToken ;
}
String errorMessage = " No " + GCUBE_TOKEN + " as Property saved in the " + ANALYTICS_RESOLVER_SERVICE_ENDPOINT_NAME + " SE registered in the scope: " + ScopeProvider . instance . get ( ) ;
logger . error ( errorMessage ) ;
throw ExceptionManager . internalErrorException ( req , errorMessage , AnalyticsCreateResolver . class , helpURI ) ;
} catch ( Exception e ) {
String errorMessage = " Error occurred on reading the " + ANALYTICS_RESOLVER_SERVICE_ENDPOINT_NAME + " SE registered in the scope: " + ScopeProvider . instance . get ( ) ;
logger . error ( errorMessage , e ) ;
throw ExceptionManager . internalErrorException ( req , errorMessage , AnalyticsCreateResolver . class , helpURI ) ;
} finally {
if ( origalScope ! = null )
ScopeProvider . instance . reset ( ) ;
}
}
2018-12-07 11:28:37 +01:00
2018-12-05 16:58:44 +01:00
/ * *
* Creates the temp file .
*
* @param fileName the file name
* @param extension the extension
* @param data the data
* @return the file
* @throws IOException Signals that an I / O exception has occurred .
* /
private static File createTempFile ( String fileName , String extension , byte [ ] data ) throws IOException {
// Since Java 1.7 Files and Path API simplify operations on files
java . nio . file . Path path = Files . createTempFile ( fileName , extension ) ;
File file = path . toFile ( ) ;
// writing sample data
Files . write ( path , data ) ;
2018-12-12 15:38:44 +01:00
logger . info ( " Created the Temp File: " + file . getAbsolutePath ( ) ) ;
2018-12-05 16:58:44 +01:00
return file ;
}
2018-12-07 11:28:37 +01:00
/ * *
* Creates the dm invocation file name .
*
* @param operatorId the operator id
* @return the string
* /
private static String createDMInvocationFileName ( String operatorId ) {
String fileName = " dim " ;
int index = operatorId . lastIndexOf ( " . " ) ;
if ( index > 0 & & index < operatorId . length ( ) ) {
fileName + = " - " + operatorId . substring ( index + 1 , operatorId . length ( ) ) ;
}
2018-12-12 15:38:44 +01:00
fileName + = " - " + System . currentTimeMillis ( ) ;
2018-12-07 11:28:37 +01:00
return fileName ;
}
2018-12-17 15:12:59 +01:00
public static void main ( String [ ] args ) {
System . out . println ( readApplicationTokenFromSE ( null , " /gcube " ) ) ;
}
2018-12-05 16:58:44 +01:00
}