2017-05-17 16:45:38 +02:00
package org.gcube.data.transfer.service.transfers ;
2017-11-27 17:45:28 +01:00
import java.io.File ;
2017-05-17 16:45:38 +02:00
import java.io.InputStream ;
import java.net.MalformedURLException ;
import java.net.URL ;
2017-05-29 17:45:29 +02:00
import java.util.Set ;
2017-05-17 16:45:38 +02:00
2017-11-27 17:45:28 +01:00
import javax.activation.MimetypesFileTypeMap ;
2017-05-17 16:45:38 +02:00
import javax.inject.Inject ;
import javax.ws.rs.Consumes ;
2017-12-05 16:03:12 +01:00
import javax.ws.rs.DELETE ;
2017-05-17 16:45:38 +02:00
import javax.ws.rs.DefaultValue ;
2017-11-27 17:45:28 +01:00
import javax.ws.rs.GET ;
2020-04-08 16:05:43 +02:00
import javax.ws.rs.HEAD ;
2017-05-17 16:45:38 +02:00
import javax.ws.rs.POST ;
import javax.ws.rs.Path ;
import javax.ws.rs.PathParam ;
import javax.ws.rs.Produces ;
import javax.ws.rs.QueryParam ;
import javax.ws.rs.WebApplicationException ;
import javax.ws.rs.core.MediaType ;
2017-11-27 17:45:28 +01:00
import javax.ws.rs.core.Response ;
2017-05-17 16:45:38 +02:00
import javax.ws.rs.core.Response.Status ;
2017-12-05 16:03:12 +01:00
import org.gcube.data.transfer.model.DeletionReport ;
2017-05-17 16:45:38 +02:00
import org.gcube.data.transfer.model.Destination ;
import org.gcube.data.transfer.model.DestinationClashPolicy ;
2017-05-29 17:45:29 +02:00
import org.gcube.data.transfer.model.PluginInvocation ;
2020-04-08 16:05:43 +02:00
import org.gcube.data.transfer.model.RemoteFileDescriptor ;
2017-05-17 16:45:38 +02:00
import org.gcube.data.transfer.model.ServiceConstants ;
import org.gcube.data.transfer.model.TransferRequest ;
import org.gcube.data.transfer.model.TransferTicket ;
import org.gcube.data.transfer.model.options.FileUploadOptions ;
import org.gcube.data.transfer.model.options.HttpDownloadOptions ;
import org.gcube.data.transfer.model.options.TransferOptions.TransferMethod ;
import org.gcube.data.transfer.model.settings.FileUploadSettings ;
import org.gcube.data.transfer.model.settings.HttpDownloadSettings ;
2020-04-10 17:38:00 +02:00
import org.gcube.data.transfer.service.DTServiceAppManager ;
2018-02-23 10:45:03 +01:00
import org.gcube.data.transfer.service.transfers.engine.AccountingManager ;
2017-11-27 17:45:28 +01:00
import org.gcube.data.transfer.service.transfers.engine.PersistenceProvider ;
2017-05-17 16:45:38 +02:00
import org.gcube.data.transfer.service.transfers.engine.RequestManager ;
2017-11-27 17:45:28 +01:00
import org.gcube.data.transfer.service.transfers.engine.faults.DestinationAccessException ;
2020-04-10 17:38:00 +02:00
import org.gcube.data.transfer.service.transfers.engine.impl.AccountingManagerImpl ;
import org.gcube.smartgears.annotations.ManagedBy ;
2017-05-17 16:45:38 +02:00
import org.glassfish.jersey.media.multipart.FormDataContentDisposition ;
import org.glassfish.jersey.media.multipart.FormDataParam ;
import lombok.extern.slf4j.Slf4j ;
2017-11-27 17:45:28 +01:00
@Path ( ServiceConstants . REST_SERVLET_NAME + " /{destinationId}/{subPath : \\ S*} " )
2017-05-17 16:45:38 +02:00
@Slf4j
2020-04-10 17:38:00 +02:00
@ManagedBy ( DTServiceAppManager . class )
2017-05-17 16:45:38 +02:00
public class REST {
2017-11-27 17:45:28 +01:00
@PathParam ( " destinationId " ) String destinationID ;
@PathParam ( " subPath " ) String subPath ;
2017-05-17 16:45:38 +02:00
2017-11-27 17:45:28 +01:00
@Inject
RequestManager requests ;
@Inject
PersistenceProvider persistence ;
2017-05-29 17:45:29 +02:00
2017-11-27 17:45:28 +01:00
@POST
2017-05-17 16:45:38 +02:00
@Consumes ( MediaType . WILDCARD )
2017-11-27 17:45:28 +01:00
@Produces ( MediaType . APPLICATION_JSON )
public Object serveFileUpload ( @QueryParam ( " method " ) @DefaultValue ( " FileUpload " ) String methodString ,
@QueryParam ( ServiceConstants . DESTINATION_FILE_NAME ) String destinationFileName ,
@QueryParam ( ServiceConstants . CREATE_DIRS ) @DefaultValue ( " true " ) Boolean createDirs ,
@QueryParam ( ServiceConstants . ON_EXISTING_FILE ) @DefaultValue ( " ADD_SUFFIX " ) DestinationClashPolicy onExistingFile ,
@QueryParam ( ServiceConstants . ON_EXISTING_DIR ) @DefaultValue ( " APPEND " ) DestinationClashPolicy onExistingDirectory ,
@QueryParam ( ServiceConstants . SOURCE_ID ) String sourceID ,
@FormDataParam ( ServiceConstants . MULTIPART_FILE ) InputStream uploadedFile ,
@FormDataParam ( ServiceConstants . MULTIPART_FILE ) FormDataContentDisposition uploadedFileDetails ,
@FormDataParam ( " plugin-invocations " ) Set < PluginInvocation > pluginInvocations ) {
2017-05-17 16:45:38 +02:00
try {
2017-11-27 17:45:28 +01:00
String pathString = " < " + destinationID + " >/ " + subPath ;
log . info ( " Received POST request at {} " , pathString ) ;
2017-05-29 17:45:29 +02:00
log . debug ( " Plugin invocation set : {} " , pluginInvocations ) ;
2017-11-27 17:45:28 +01:00
TransferRequest request = formRequestFromREST ( methodString , destinationID , subPath , pluginInvocations ,
createDirs , onExistingFile , onExistingDirectory ,
uploadedFile , uploadedFileDetails , destinationFileName , sourceID ) ;
2017-05-29 17:45:29 +02:00
log . info ( " Received REST Request {} " , request ) ;
2017-05-17 16:45:38 +02:00
2017-05-29 17:45:29 +02:00
TransferTicket ticket = requests . put ( request ) ;
2017-05-17 16:45:38 +02:00
2017-05-29 17:45:29 +02:00
if ( ticket . getSettings ( ) . getOptions ( ) . getMethod ( ) . equals ( TransferMethod . FileUpload ) )
{
log . debug ( " Resulting sync ticket {} " , ticket ) ;
2017-05-17 16:45:38 +02:00
2017-05-29 17:45:29 +02:00
return ticket ;
2017-05-17 16:45:38 +02:00
}
2017-05-29 17:45:29 +02:00
else {
return ticket ;
}
2017-05-17 16:45:38 +02:00
} catch ( WebApplicationException e ) {
log . error ( " Unable to serve request " , e ) ;
throw e ;
}
}
2017-11-27 17:45:28 +01:00
private TransferRequest formRequestFromREST ( String methodString , String destinationID , String subPath , Set < PluginInvocation > pluginInvocations ,
Boolean createDirs , DestinationClashPolicy onExistingFile ,
DestinationClashPolicy onExistingDirectory ,
InputStream uploadedFile ,
FormDataContentDisposition uploadedFileDetails ,
String destinationFileName ,
String sourceID ) {
2017-05-17 16:45:38 +02:00
log . info ( " Creating TransferRequest from REST invocation method : {}, dest ID {}, sub Path {} " , methodString , destinationID , subPath ) ;
TransferMethod method = null ;
try {
method = TransferMethod . valueOf ( methodString ) ;
} catch ( Throwable t ) {
2017-11-27 17:45:28 +01:00
throw new WebApplicationException ( " Invalid selected method " + methodString , t , Status . BAD_REQUEST ) ; }
2017-05-17 16:45:38 +02:00
Destination destination = new Destination ( ) ;
destination . setCreateSubfolders ( createDirs ) ;
destination . setPersistenceId ( destinationID ) ;
destination . setSubFolder ( subPath ) ;
destination . setOnExistingSubFolder ( onExistingDirectory ) ;
2017-07-05 14:31:27 +02:00
destination . setOnExistingFileName ( onExistingFile ) ;
2017-11-27 17:45:28 +01:00
2017-05-17 16:45:38 +02:00
TransferRequest resultingRequest = new TransferRequest ( ) ;
2017-05-29 17:45:29 +02:00
resultingRequest . setDestinationSettings ( destination ) ;
resultingRequest . setPluginInvocations ( pluginInvocations ) ;
2017-05-17 16:45:38 +02:00
switch ( method ) {
case FileUpload : {
2017-05-29 17:45:29 +02:00
// if(destinationFileName==null) throw new WebApplicationException("Parameter "+ServiceConstants.DESTINATION_FILE_NAME+" is mandatory.",Status.BAD_REQUEST);
2017-05-17 16:45:38 +02:00
if ( uploadedFileDetails = = null ) throw new WebApplicationException ( " Missing multipart " + ServiceConstants . MULTIPART_FILE + " details. " , Status . BAD_REQUEST ) ;
if ( uploadedFile = = null ) throw new WebApplicationException ( " Missing multipart " + ServiceConstants . MULTIPART_FILE + " stream. " , Status . BAD_REQUEST ) ;
destination . setDestinationFileName ( destinationFileName ! = null ? destinationFileName : uploadedFileDetails . getFileName ( ) ) ;
FileUploadSettings uploadSettings = new FileUploadSettings ( uploadedFile , new FileUploadOptions ( ) ) ;
resultingRequest . setSettings ( uploadSettings ) ;
break ;
}
case DirectTransfer : {
throw new WebApplicationException ( " Unsupported selected method " + methodString , Status . BAD_REQUEST ) ;
}
case HTTPDownload : {
if ( sourceID = = null ) throw new WebApplicationException ( " Parameter " + ServiceConstants . SOURCE_ID + " is mandatory. " , Status . BAD_REQUEST ) ;
2017-12-18 16:25:26 +01:00
if ( destinationFileName ! = null ) destination . setDestinationFileName ( destinationFileName ) ;
2017-05-17 16:45:38 +02:00
try {
HttpDownloadSettings settings = new HttpDownloadSettings ( new URL ( sourceID ) , new HttpDownloadOptions ( ) ) ;
resultingRequest . setSettings ( settings ) ;
break ;
} catch ( MalformedURLException e ) {
2017-11-27 17:45:28 +01:00
throw new WebApplicationException ( " Source " + sourceID + " is not a valid URL. " , e , Status . BAD_REQUEST ) ;
2017-05-17 16:45:38 +02:00
}
}
default : throw new WebApplicationException ( " Unsupported selected method " + methodString , Status . BAD_REQUEST ) ;
}
return resultingRequest ;
}
2017-11-27 17:45:28 +01:00
2017-12-05 16:03:12 +01:00
2017-11-27 17:45:28 +01:00
@GET
@Produces ( " */* " )
2017-12-05 18:18:13 +01:00
public Response getFile (
2017-11-27 17:45:28 +01:00
@QueryParam ( " descriptor " ) @DefaultValue ( " false " ) Boolean getDescriptor ) {
String pathString = " < " + destinationID + " >/ " + subPath ;
log . info ( " Received GET request at {} , descriptor option is {} " , pathString , getDescriptor ) ;
2018-02-23 10:45:03 +01:00
long volume = 0l ;
boolean success = true ;
2018-02-28 11:41:49 +01:00
String path = destinationID + " : " + subPath ;
2018-02-23 10:45:03 +01:00
String mimeType = " N/A " ;
2017-11-27 17:45:28 +01:00
try {
2017-12-05 18:18:13 +01:00
if ( getDescriptor ) return Response . ok ( persistence . getDescriptor ( destinationID , subPath ) , MediaType . APPLICATION_JSON_TYPE ) . build ( ) ;
2017-11-27 17:45:28 +01:00
2018-02-23 10:45:03 +01:00
2017-12-05 18:18:13 +01:00
File persisted = persistence . getPersistedFile ( destinationID , subPath ) ;
2017-11-27 17:45:28 +01:00
if ( ! persisted . exists ( ) ) throw new WebApplicationException ( " File " + pathString + " doesn't exists. " , Status . NOT_FOUND ) ;
if ( persisted . isDirectory ( ) ) throw new WebApplicationException ( " The selected path " + pathString + " is a directory. " , Status . BAD_REQUEST ) ;
2018-02-23 10:45:03 +01:00
mimeType = new MimetypesFileTypeMap ( ) . getContentType ( persisted ) ;
volume = persisted . length ( ) ;
return Response . ok ( persisted , mimeType ) . build ( ) ;
} catch ( DestinationAccessException e ) {
success = false ;
2017-11-27 17:45:28 +01:00
throw new WebApplicationException ( " Unable to access selected path " + pathString , e , Status . INTERNAL_SERVER_ERROR ) ;
2018-02-23 10:45:03 +01:00
} finally {
if ( ! getDescriptor )
account ( true , volume , success , path , mimeType ) ;
2017-11-27 17:45:28 +01:00
}
}
2020-04-08 16:05:43 +02:00
@HEAD
@Produces ( MediaType . APPLICATION_JSON )
public RemoteFileDescriptor getDescriptor ( ) {
String pathString = " < " + destinationID + " >/ " + subPath ;
try {
log . info ( " Received HEAD request at {} , descriptor option is {} " , pathString ) ;
return persistence . getDescriptor ( destinationID , subPath ) ;
} catch ( DestinationAccessException e ) {
throw new WebApplicationException ( " Unable to access selected path " + pathString , e , Status . INTERNAL_SERVER_ERROR ) ;
}
}
2017-12-05 16:03:12 +01:00
@DELETE
@Produces ( MediaType . APPLICATION_JSON )
2017-12-05 18:18:13 +01:00
public DeletionReport deleteFile ( ) {
2017-12-05 16:03:12 +01:00
String pathString = " < " + destinationID + " >/ " + subPath ;
log . info ( " Received DELETE request at {} " , pathString ) ;
2018-02-23 10:45:03 +01:00
long volume = 0l ;
boolean success = true ;
2018-02-28 11:41:49 +01:00
String path = destinationID + " : " + subPath ;
2018-02-23 10:45:03 +01:00
String mimeType = " N/A " ;
2017-12-05 16:03:12 +01:00
try {
2018-02-23 10:45:03 +01:00
File theFile = persistence . getPersistedFile ( destinationID , subPath ) ;
volume = theFile . length ( ) ;
mimeType = new MimetypesFileTypeMap ( ) . getContentType ( theFile ) ;
2017-12-05 18:18:13 +01:00
return persistence . delete ( destinationID , subPath ) ;
2017-12-05 16:03:12 +01:00
} catch ( DestinationAccessException e ) {
throw new WebApplicationException ( " Unable to access selected path " + pathString , e , Status . INTERNAL_SERVER_ERROR ) ;
2018-02-23 10:45:03 +01:00
} finally {
account ( false , volume , success , path , mimeType ) ;
2017-12-05 16:03:12 +01:00
}
}
2018-02-23 10:45:03 +01:00
private static void account ( boolean read , long volume , boolean success , String path , String mimetype ) {
2020-04-10 17:38:00 +02:00
AccountingManager manager = AccountingManagerImpl . get ( ) ;
2018-02-23 10:45:03 +01:00
String id = manager . createNewRecord ( ) ;
if ( read ) manager . setRead ( id ) ;
else manager . setDelete ( id ) ;
manager . setSuccessful ( id , success ) ;
manager . setVolumne ( id , volume ) ;
manager . setMimeType ( id , mimetype ) ;
manager . setResourceURI ( id , path ) ;
manager . account ( id ) ;
}
2017-05-17 16:45:38 +02:00
}