commit 6db6c31cbea9c980ba493edaa451bcfb508e0b39 Author: fabio.sinibaldi Date: Wed May 17 14:45:38 2017 +0000 git-svn-id: http://svn.research-infrastructures.eu/public/d4science/gcube/branches/data-transfer/data-transfer-service/2.0@148792 82a268e6-3cf1-43bd-a215-b396298e98cf diff --git a/.classpath b/.classpath new file mode 100644 index 0000000..4591c00 --- /dev/null +++ b/.classpath @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/.project b/.project new file mode 100644 index 0000000..b967d5f --- /dev/null +++ b/.project @@ -0,0 +1,42 @@ + + + data-transfer-service + + + + + + org.eclipse.wst.jsdt.core.javascriptValidator + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.wst.common.project.facet.core.builder + + + + + org.eclipse.wst.validation.validationbuilder + + + + + org.eclipse.m2e.core.maven2Builder + + + + + + org.eclipse.jem.workbench.JavaEMFNature + org.eclipse.wst.common.modulecore.ModuleCoreNature + org.eclipse.jdt.core.javanature + org.eclipse.m2e.core.maven2Nature + org.eclipse.wst.common.project.facet.core.nature + org.eclipse.wst.jsdt.core.jsNature + + diff --git a/.settings/.jsdtscope b/.settings/.jsdtscope new file mode 100644 index 0000000..b46b920 --- /dev/null +++ b/.settings/.jsdtscope @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/.settings/org.eclipse.core.resources.prefs b/.settings/org.eclipse.core.resources.prefs new file mode 100644 index 0000000..29abf99 --- /dev/null +++ b/.settings/org.eclipse.core.resources.prefs @@ -0,0 +1,6 @@ +eclipse.preferences.version=1 +encoding//src/main/java=UTF-8 +encoding//src/main/resources=UTF-8 +encoding//src/test/java=UTF-8 +encoding//src/test/resources=UTF-8 +encoding/=UTF-8 diff --git a/.settings/org.eclipse.jdt.core.prefs b/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000..443e085 --- /dev/null +++ b/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,8 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7 +org.eclipse.jdt.core.compiler.compliance=1.7 +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning +org.eclipse.jdt.core.compiler.source=1.7 diff --git a/.settings/org.eclipse.m2e.core.prefs b/.settings/org.eclipse.m2e.core.prefs new file mode 100644 index 0000000..ff7698f --- /dev/null +++ b/.settings/org.eclipse.m2e.core.prefs @@ -0,0 +1,4 @@ +activeProfiles= +eclipse.preferences.version=1 +resolveWorkspaceProjects=false +version=1 diff --git a/.settings/org.eclipse.wst.common.component b/.settings/org.eclipse.wst.common.component new file mode 100755 index 0000000..0eff87a --- /dev/null +++ b/.settings/org.eclipse.wst.common.component @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/.settings/org.eclipse.wst.common.project.facet.core.prefs.xml b/.settings/org.eclipse.wst.common.project.facet.core.prefs.xml new file mode 100644 index 0000000..cc81385 --- /dev/null +++ b/.settings/org.eclipse.wst.common.project.facet.core.prefs.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/.settings/org.eclipse.wst.common.project.facet.core.xml b/.settings/org.eclipse.wst.common.project.facet.core.xml new file mode 100644 index 0000000..d3e543c --- /dev/null +++ b/.settings/org.eclipse.wst.common.project.facet.core.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/.settings/org.eclipse.wst.jsdt.ui.superType.container b/.settings/org.eclipse.wst.jsdt.ui.superType.container new file mode 100644 index 0000000..3bd5d0a --- /dev/null +++ b/.settings/org.eclipse.wst.jsdt.ui.superType.container @@ -0,0 +1 @@ +org.eclipse.wst.jsdt.launching.baseBrowserLibrary \ No newline at end of file diff --git a/.settings/org.eclipse.wst.jsdt.ui.superType.name b/.settings/org.eclipse.wst.jsdt.ui.superType.name new file mode 100644 index 0000000..05bd71b --- /dev/null +++ b/.settings/org.eclipse.wst.jsdt.ui.superType.name @@ -0,0 +1 @@ +Window \ No newline at end of file diff --git a/.settings/org.eclipse.wst.validation.prefs b/.settings/org.eclipse.wst.validation.prefs new file mode 100644 index 0000000..04cad8c --- /dev/null +++ b/.settings/org.eclipse.wst.validation.prefs @@ -0,0 +1,2 @@ +disabled=06target +eclipse.preferences.version=1 diff --git a/distro/LICENSE b/distro/LICENSE new file mode 100644 index 0000000..2d9616a --- /dev/null +++ b/distro/LICENSE @@ -0,0 +1 @@ +${gcube.license} \ No newline at end of file diff --git a/distro/README b/distro/README new file mode 100644 index 0000000..12bcf19 --- /dev/null +++ b/distro/README @@ -0,0 +1,65 @@ +The gCube System - ${name} +-------------------------------------------------- + +${description} + + +${gcube.description} + +${gcube.funding} + + +Version +-------------------------------------------------- + +${version} (${buildDate}) + +Please see the file named "changelog.xml" in this directory for the release notes. + + + +Authors +-------------------------------------------------- + +* Fabio Sinibaldi (fabio.sinibaldi-AT-isti.cnr.it) Istituto di Scienza e Tecnologie dell'Informazione "A. Faedo" - CNR, Pisa (Italy). + +Maintainers +----------- + +* Fabio Sinibaldi (fabio.sinibaldi-AT-isti.cnr.it) Istituto di Scienza e Tecnologie dell'Informazione "A. Faedo" - CNR, Pisa (Italy). + + +Download information +-------------------------------------------------- + +Source code is available from SVN: + ${scm.url} + +Binaries can be downloaded from the gCube website: + ${gcube.website} + +Installation +-------------------------------------------------- + +Installation documentation is available on-line in the gCube Wiki: + ${gcube.wikiRoot}/Data_Transfer_2 + +Documentation +-------------------------------------------------- + +Documentation is available on-line in the gCube Wiki: + ${gcube.wikiRoot}/Data_Transfer_2 + ${gcube.wikiRoot}/How_to_use_Data_Transfer_2 + + +Support +-------------------------------------------------- + +Bugs and support requests can be reported in the gCube issue tracking tool: + ${gcube.issueTracking} + + +Licensing +-------------------------------------------------- + +This software is licensed under the terms you may find in the file named "LICENSE" in this directory. \ No newline at end of file diff --git a/distro/changelog.xml b/distro/changelog.xml new file mode 100644 index 0000000..01ec4cf --- /dev/null +++ b/distro/changelog.xml @@ -0,0 +1,13 @@ + + + First Release + + + Added Destination + Added Plugin + + + Improved plugin management + Endorsed decompress-plugin + + \ No newline at end of file diff --git a/distro/descriptor.xml b/distro/descriptor.xml new file mode 100644 index 0000000..dc46ade --- /dev/null +++ b/distro/descriptor.xml @@ -0,0 +1,30 @@ + + servicearchive + + tar.gz + + / + + + ${distroDirectory} + / + true + + README + LICENSE + changelog.xml + + 755 + true + + + + + target/${build.finalName}.${project.packaging} + /${artifactId} + + + \ No newline at end of file diff --git a/distro/gcube-app.xml b/distro/gcube-app.xml new file mode 100644 index 0000000..e3adfda --- /dev/null +++ b/distro/gcube-app.xml @@ -0,0 +1,11 @@ + + data-transfer-service + DataTransfer + ${version} + Data Tansfer Service + + + + diff --git a/distro/profile.xml b/distro/profile.xml new file mode 100644 index 0000000..0e4e15c --- /dev/null +++ b/distro/profile.xml @@ -0,0 +1,27 @@ + + + + Service + + ${description} + DataTransfer + ${artifactId} + 1.0.0 + + + ${artifactId} + ${version} + + ${groupId} + ${artifactId} + ${version} + + + ${build.finalName}.jar + + + + + + + diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..fafc5e9 --- /dev/null +++ b/pom.xml @@ -0,0 +1,245 @@ + + 4.0.0 + + org.gcube.tools + maven-parent + LATEST + + org.gcube.data.transfer + data-transfer-service + 2.0.0-SNAPSHOT + war + DataTransferService + + https://svn.d4science.research-infrastructures.eu/gcube/trunk/data-transfer/${project.artifactId} + + + + ${project.basedir}/src/main/webapp/WEB-INF + ${project.basedir}/distro + 2.14 + 2.14 + 2.2.4.Final + + + + + + org.gcube.distribution + maven-smartgears-bom + LATEST + pom + import + + + + + + + + org.gcube.data.transfer + data-transfer-plugin-framework + [1.0.0-SNAPSHOT,2.0.0-SNAPSHOT) + + + + + org.gcube.data.transfer + decompress-archive-plugin + [1.0.0-SNAPSHOT,2.0.0-SNAPSHOT) + + + + + + org.slf4j + slf4j-api + + + + org.gcube.core + common-smartgears-app + + + org.gcube.core + common-smartgears + + + + org.apache.commons + commons-io + 1.3.2 + + + + + + javax.ws.rs + javax.ws.rs-api + 2.0 + + + org.glassfish.jersey.containers + jersey-container-servlet + ${jersey-version} + + + org.glassfish.jersey.containers.glassfish + jersey-gf-cdi + ${jersey-cdi-version} + + + + javax.transaction + javax.transaction-api + 1.2 + + + javax.servlet + javax.servlet-api + 3.0.1 + provided + + + + org.glassfish.jersey.media + jersey-media-json-jackson + ${jersey-version} + + + + + + + + + + + org.glassfish.jersey.media + jersey-media-multipart + ${jersey-version} + + + + org.glassfish.jersey.bundles + jaxrs-ri + ${jersey-version} + + + + org.glassfish.jersey.core + jersey-common + ${jersey-version} + + + + + javax.enterprise + cdi-api + 1.2 + + + org.jboss.weld.servlet + weld-servlet + ${weld-version} + + + org.jboss + jandex + 1.2.2.Final + + + + + + ch.qos.logback + logback-classic + 1.0.13 + test + + + + org.glassfish.jersey.test-framework.providers + jersey-test-framework-provider-simple + ${jersey-version} + test + + + + junit + junit + 4.12 + test + + + + + + + ${project.artifactId} + + + maven-compiler-plugin + 2.3.2 + + 1.7 + 1.7 + + + + org.apache.maven.plugins + maven-war-plugin + 2.4 + + data-transfer-service + false + + + + org.apache.maven.plugins + maven-resources-plugin + 2.6 + + + copy-profile + + copy-resources + + process-resources + + ${webappDirectory} + + + ${distroDirectory} + true + + + + + + + + org.apache.maven.plugins + maven-assembly-plugin + 2.2 + + + ${distroDirectory}/descriptor.xml + + + + + servicearchive + install + + single + + + + + + + + Service used to receive data from other hosting nodes + \ No newline at end of file diff --git a/src/main/java/org/gcube/data/transfer/service/DTService.java b/src/main/java/org/gcube/data/transfer/service/DTService.java new file mode 100644 index 0000000..48eb7ab --- /dev/null +++ b/src/main/java/org/gcube/data/transfer/service/DTService.java @@ -0,0 +1,21 @@ +package org.gcube.data.transfer.service; + +import javax.ws.rs.ApplicationPath; + +import org.gcube.data.transfer.model.ServiceConstants; +import org.glassfish.jersey.media.multipart.MultiPartFeature; +import org.glassfish.jersey.server.ResourceConfig; + +@ApplicationPath(ServiceConstants.APPLICATION_PATH) +public class DTService extends ResourceConfig{ + + public DTService() { + super(); + packages("org.gcube.data.transfer.service.transfers"); + packages("org.glassfish.jersey.media.multipart"); + packages("org.glassfish.jersey.media.multipart.internal"); +// register(ProviderLoggingListener.class); + register(MultiPartFeature.class); + } + +} diff --git a/src/main/java/org/gcube/data/transfer/service/DTServiceAppManager.java b/src/main/java/org/gcube/data/transfer/service/DTServiceAppManager.java new file mode 100644 index 0000000..39c1e64 --- /dev/null +++ b/src/main/java/org/gcube/data/transfer/service/DTServiceAppManager.java @@ -0,0 +1,40 @@ +package org.gcube.data.transfer.service; + +import javax.inject.Inject; + +import org.gcube.data.transfer.service.transfers.engine.RequestManager; +import org.gcube.data.transfer.service.transfers.engine.TicketManager; +import org.gcube.smartgears.ApplicationManager; +import org.gcube.smartgears.ContextProvider; +import org.gcube.smartgears.context.application.ApplicationContext; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class DTServiceAppManager implements ApplicationManager { + + @Inject + RequestManager requests; + @Inject + TicketManager tickets; + + ApplicationContext ctx = ContextProvider.get(); + + @Override + public void onInit() { + log.info("DT Application init"); + + + + } + + @Override + public void onShutdown() { + log.info("DT Application shutdown"); + log.debug("Shutting down request manager ..."); + requests.shutdown(); + log.debug("Shutting down ticket manager"); + tickets.shutdown(); + log.info("Done"); + } + } \ No newline at end of file diff --git a/src/main/java/org/gcube/data/transfer/service/ProviderLoggingListener.java b/src/main/java/org/gcube/data/transfer/service/ProviderLoggingListener.java new file mode 100644 index 0000000..ac7fb44 --- /dev/null +++ b/src/main/java/org/gcube/data/transfer/service/ProviderLoggingListener.java @@ -0,0 +1,40 @@ +package org.gcube.data.transfer.service; + +import java.util.Set; + +import javax.ws.rs.ext.Provider; + +import org.glassfish.jersey.server.ResourceConfig; +import org.glassfish.jersey.server.model.ResourceModel; +import org.glassfish.jersey.server.monitoring.ApplicationEvent; +import org.glassfish.jersey.server.monitoring.ApplicationEventListener; +import org.glassfish.jersey.server.monitoring.RequestEvent; +import org.glassfish.jersey.server.monitoring.RequestEventListener; + +@Provider +public class ProviderLoggingListener implements ApplicationEventListener { + + @Override + public void onEvent(ApplicationEvent event) { + switch (event.getType()) { + case INITIALIZATION_FINISHED: { + System.out.println("*************** LISTING PROVIDERS ******************"); + + for(Class c: event.getProviders()){ + System.out.println(c.getCanonicalName()+" \t "+ c); + } + + System.out.println("*************** RESOURCE CONFIG ******************"); + System.out.println(event.getResourceConfig()); + System.out.println("*************** RESOURCE MODEL ******************"); + System.out.println(event.getResourceModel()); + break; + } + } + } + + @Override + public RequestEventListener onRequest(RequestEvent requestEvent) { + return null; + } +} diff --git a/src/main/java/org/gcube/data/transfer/service/transfers/Capabilities.java b/src/main/java/org/gcube/data/transfer/service/transfers/Capabilities.java new file mode 100644 index 0000000..db18b04 --- /dev/null +++ b/src/main/java/org/gcube/data/transfer/service/transfers/Capabilities.java @@ -0,0 +1,41 @@ +package org.gcube.data.transfer.service.transfers; + +import javax.inject.Inject; +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.WebApplicationException; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response.Status; + +import org.gcube.data.transfer.model.ServiceConstants; +import org.gcube.data.transfer.model.TransferCapabilities; +import org.gcube.data.transfer.service.transfers.engine.CapabilitiesProvider; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@Path(ServiceConstants.CAPABILTIES_SERVLET_NAME) +public class Capabilities { + + @Inject + CapabilitiesProvider provider; + + + + + @GET + @Produces(MediaType.APPLICATION_JSON) + public TransferCapabilities getCapabilities(){ + log.debug("Serving get capabilities"); + try{ + TransferCapabilities toReturn=provider.get(); + log.debug("No exceptions here.. returning "+toReturn); + return toReturn; + }catch(Exception e){ + log.debug("Unable to return capabilities.",e); + throw new WebApplicationException(Status.INTERNAL_SERVER_ERROR); + } + } + +} diff --git a/src/main/java/org/gcube/data/transfer/service/transfers/REST.java b/src/main/java/org/gcube/data/transfer/service/transfers/REST.java new file mode 100644 index 0000000..9ce5fdc --- /dev/null +++ b/src/main/java/org/gcube/data/transfer/service/transfers/REST.java @@ -0,0 +1,138 @@ +package org.gcube.data.transfer.service.transfers; + +import java.io.InputStream; +import java.net.MalformedURLException; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; + +import javax.inject.Inject; +import javax.ws.rs.Consumes; +import javax.ws.rs.DefaultValue; +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; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.Response.Status; + +import org.gcube.data.transfer.model.Destination; +import org.gcube.data.transfer.model.DestinationClashPolicy; +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; +import org.gcube.data.transfer.service.transfers.engine.RequestManager; +import org.glassfish.jersey.media.multipart.FormDataContentDisposition; +import org.glassfish.jersey.media.multipart.FormDataParam; + +import lombok.extern.slf4j.Slf4j; + +@Path(ServiceConstants.REST_SERVLET_NAME) +@Slf4j +public class REST { + + + @Inject + RequestManager requests; + + + // @Inject + // PersistenceProvider persistenceProvider; + // @Inject + // PluginManager pluginManager; + // + + @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; + + @POST + @Path("/{method}/{destinationId}/{subPath: .*}") + @Consumes(MediaType.WILDCARD) + @Produces(MediaType.APPLICATION_JSON) + public Object serveFileUpload(@PathParam("method") String methodString, + @PathParam("destinationId") String destinationID, @PathParam("subPath") String subPath){ + try{ + + TransferRequest request=formRequestFromREST(methodString, destinationID, subPath); + log.info("Received REST Request {} ",request); + + + TransferTicket ticket=requests.put(request); + + if(ticket.getSettings().getOptions().getMethod().equals(TransferMethod.FileUpload)) + try { + return Response.created(new URI(ticket.getDestinationFileName())).build(); + } catch (URISyntaxException e) { + throw new WebApplicationException("Internal ERROR "+e.getMessage(),e); + } + else{ + return ticket; + } + }catch(WebApplicationException e){ + log.error("Unable to serve request",e); + throw e; + } + } + + + + private TransferRequest formRequestFromREST(String methodString,String destinationID,String subPath){ + 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) { + throw new WebApplicationException("Invalid selected method "+methodString,Status.BAD_REQUEST);} + + Destination destination=new Destination(); + destination.setCreateSubfolders(createDirs); + destination.setPersistenceId(destinationID); + destination.setSubFolder(subPath); + destination.setOnExistingSubFolder(onExistingDirectory); + + TransferRequest resultingRequest=new TransferRequest(); + resultingRequest.setDestinationSettings(destination); + + switch(method){ + case FileUpload : { +// if(destinationFileName==null) throw new WebApplicationException("Parameter "+ServiceConstants.DESTINATION_FILE_NAME+" is mandatory.",Status.BAD_REQUEST); + 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); + destination.setDestinationFileName(destinationFileName==null?sourceID:destinationFileName); + try{ + HttpDownloadSettings settings=new HttpDownloadSettings(new URL(sourceID), new HttpDownloadOptions()); + resultingRequest.setSettings(settings); + break; + }catch(MalformedURLException e){ + throw new WebApplicationException("Source "+sourceID+" is not a valid URL.",Status.BAD_REQUEST); + } + } + default: throw new WebApplicationException("Unsupported selected method "+methodString,Status.BAD_REQUEST); + } + return resultingRequest; + } + +} diff --git a/src/main/java/org/gcube/data/transfer/service/transfers/Requests.java b/src/main/java/org/gcube/data/transfer/service/transfers/Requests.java new file mode 100644 index 0000000..ffd95f4 --- /dev/null +++ b/src/main/java/org/gcube/data/transfer/service/transfers/Requests.java @@ -0,0 +1,68 @@ +package org.gcube.data.transfer.service.transfers; + +import javax.inject.Inject; +import javax.validation.constraints.NotNull; +import javax.ws.rs.Consumes; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; + +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.service.transfers.engine.RequestManager; + +import lombok.extern.slf4j.Slf4j; + + +@Path(ServiceConstants.REQUESTS_SERVLET_NAME) +@Slf4j +public class Requests { + + @Inject + RequestManager requests; + + + + //********************* INJECT PARAMS + @POST + @Produces(MediaType.APPLICATION_JSON) + @Consumes(MediaType.APPLICATION_JSON) + public TransferTicket submitRequest(@NotNull TransferRequest theRequest){ + log.info("Received transfer request : "+theRequest); + + return requests.put(theRequest); + } + + +// @PUT +// @Path("/{method}/{destinationId}/{subPath: .*}") +// @Produces(MediaType.APPLICATION_JSON) +// public TransferTicket submitRESTRequest(@PathParam("method") String methodString, +// @PathParam("destinationId") String destinationID, @PathParam("subPath") String subPath){ +// return handleRequest(formRequestFromREST(methodString, destinationID, subPath)); +// } + + + + + + +// private TransferTicket handleRequest(TransferRequest toHandle){ +// +// toHandle.setId(UUID.randomUUID().toString()); +// boolean inserted=requests.put(toHandle); +// +// log.debug("Successfully inserted "+inserted); +// +// if(!inserted) throw new WebApplicationException(Status.INTERNAL_SERVER_ERROR); +// else +// try { +// return tickets.get(toHandle.getId()); +// } catch (TicketNotFoundException e) { +// throw new WebApplicationException(Status.INTERNAL_SERVER_ERROR); +// } +// } + +} diff --git a/src/main/java/org/gcube/data/transfer/service/transfers/TransferStatus.java b/src/main/java/org/gcube/data/transfer/service/transfers/TransferStatus.java new file mode 100644 index 0000000..0289099 --- /dev/null +++ b/src/main/java/org/gcube/data/transfer/service/transfers/TransferStatus.java @@ -0,0 +1,45 @@ +package org.gcube.data.transfer.service.transfers; + +import javax.inject.Inject; +import javax.validation.constraints.NotNull; +import javax.ws.rs.GET; +import javax.ws.rs.InternalServerErrorException; +import javax.ws.rs.NotFoundException; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; + +import lombok.extern.slf4j.Slf4j; + +import org.gcube.data.transfer.model.ServiceConstants; +import org.gcube.data.transfer.model.TransferTicket; +import org.gcube.data.transfer.service.transfers.engine.TicketManager; +import org.gcube.data.transfer.service.transfers.engine.faults.TicketNotFoundException; + +@Path(ServiceConstants.STATUS_SERVLET_NAME) +@Slf4j +public class TransferStatus { + + @Inject + private TicketManager manager; + + + + @GET + @Path("/{"+ServiceConstants.TRANSFER_ID+"}") + @Produces(MediaType.APPLICATION_JSON) + public TransferTicket getTicket(@PathParam(ServiceConstants.TRANSFER_ID)@NotNull String requestId){ + try{ + log.debug("Returning status for id "+requestId); + return manager.get(requestId); + }catch(TicketNotFoundException e){ + throw new NotFoundException(); + }catch(Throwable t){ + log.error("Unexpected exception ",t); + throw new InternalServerErrorException(); + } + } + + +} diff --git a/src/main/java/org/gcube/data/transfer/service/transfers/engine/CapabilitiesProvider.java b/src/main/java/org/gcube/data/transfer/service/transfers/engine/CapabilitiesProvider.java new file mode 100644 index 0000000..92a7969 --- /dev/null +++ b/src/main/java/org/gcube/data/transfer/service/transfers/engine/CapabilitiesProvider.java @@ -0,0 +1,8 @@ +package org.gcube.data.transfer.service.transfers.engine; + +import org.gcube.data.transfer.model.TransferCapabilities; + +public interface CapabilitiesProvider { + + public TransferCapabilities get(); +} diff --git a/src/main/java/org/gcube/data/transfer/service/transfers/engine/PersistenceProvider.java b/src/main/java/org/gcube/data/transfer/service/transfers/engine/PersistenceProvider.java new file mode 100644 index 0000000..cac2fed --- /dev/null +++ b/src/main/java/org/gcube/data/transfer/service/transfers/engine/PersistenceProvider.java @@ -0,0 +1,16 @@ +package org.gcube.data.transfer.service.transfers.engine; + +import java.io.File; +import java.util.Set; + +import org.gcube.data.transfer.model.Destination; +import org.gcube.data.transfer.service.transfers.engine.faults.DestinationAccessException; + +public interface PersistenceProvider { + + public File getPersistenceFolderById(String persistenceId) throws DestinationAccessException; + + public Set getAvaileblContextIds(); + + File prepareDestination(Destination dest) throws DestinationAccessException; +} diff --git a/src/main/java/org/gcube/data/transfer/service/transfers/engine/PluginManager.java b/src/main/java/org/gcube/data/transfer/service/transfers/engine/PluginManager.java new file mode 100644 index 0000000..1087d58 --- /dev/null +++ b/src/main/java/org/gcube/data/transfer/service/transfers/engine/PluginManager.java @@ -0,0 +1,16 @@ +package org.gcube.data.transfer.service.transfers.engine; + +import java.util.Map; + +import org.gcube.data.transfer.model.PluginDescription; +import org.gcube.data.transfer.model.PluginInvocation; +import org.gcube.data.transfer.plugin.ExecutionReport; +import org.gcube.data.transfer.service.transfers.engine.faults.PluginExecutionException; +import org.gcube.data.transfer.service.transfers.engine.faults.PluginNotFoundException; + +public interface PluginManager { + + public Map getInstalledPlugins(); + public ExecutionReport execute(PluginInvocation invocation)throws PluginNotFoundException,PluginExecutionException; + +} diff --git a/src/main/java/org/gcube/data/transfer/service/transfers/engine/RequestManager.java b/src/main/java/org/gcube/data/transfer/service/transfers/engine/RequestManager.java new file mode 100644 index 0000000..d3780d9 --- /dev/null +++ b/src/main/java/org/gcube/data/transfer/service/transfers/engine/RequestManager.java @@ -0,0 +1,12 @@ +package org.gcube.data.transfer.service.transfers.engine; + +import org.gcube.data.transfer.model.TransferRequest; +import org.gcube.data.transfer.model.TransferTicket; + +public interface RequestManager { + + public TransferTicket put(TransferRequest request); + + public void shutdown(); + +} diff --git a/src/main/java/org/gcube/data/transfer/service/transfers/engine/TicketManager.java b/src/main/java/org/gcube/data/transfer/service/transfers/engine/TicketManager.java new file mode 100644 index 0000000..c51c0b2 --- /dev/null +++ b/src/main/java/org/gcube/data/transfer/service/transfers/engine/TicketManager.java @@ -0,0 +1,20 @@ +package org.gcube.data.transfer.service.transfers.engine; + +import org.gcube.data.transfer.model.TransferTicket; +import org.gcube.data.transfer.service.transfers.engine.faults.TicketNotFoundException; + +public interface TicketManager { + + + /** + * returns true if new + * + * @param toInsert + * @return + */ + public boolean insertUpdate(TransferTicket toInsert); + + public TransferTicket get(String ticketId) throws TicketNotFoundException; + + public void shutdown(); +} diff --git a/src/main/java/org/gcube/data/transfer/service/transfers/engine/faults/DestinationAccessException.java b/src/main/java/org/gcube/data/transfer/service/transfers/engine/faults/DestinationAccessException.java new file mode 100644 index 0000000..ebfb8c5 --- /dev/null +++ b/src/main/java/org/gcube/data/transfer/service/transfers/engine/faults/DestinationAccessException.java @@ -0,0 +1,35 @@ +package org.gcube.data.transfer.service.transfers.engine.faults; + +public class DestinationAccessException extends ManagedException { + + /** + * + */ + private static final long serialVersionUID = 4968214602073818019L; + + public DestinationAccessException() { + // TODO Auto-generated constructor stub + } + + public DestinationAccessException(String message) { + super(message); + // TODO Auto-generated constructor stub + } + + public DestinationAccessException(Throwable cause) { + super(cause); + // TODO Auto-generated constructor stub + } + + public DestinationAccessException(String message, Throwable cause) { + super(message, cause); + // TODO Auto-generated constructor stub + } + + public DestinationAccessException(String message, Throwable cause, boolean enableSuppression, + boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + // TODO Auto-generated constructor stub + } + +} diff --git a/src/main/java/org/gcube/data/transfer/service/transfers/engine/faults/ManagedException.java b/src/main/java/org/gcube/data/transfer/service/transfers/engine/faults/ManagedException.java new file mode 100644 index 0000000..b28d6aa --- /dev/null +++ b/src/main/java/org/gcube/data/transfer/service/transfers/engine/faults/ManagedException.java @@ -0,0 +1,35 @@ +package org.gcube.data.transfer.service.transfers.engine.faults; + +public class ManagedException extends Exception { + + /** + * + */ + private static final long serialVersionUID = 1L; + + public ManagedException() { + // TODO Auto-generated constructor stub + } + + public ManagedException(String message) { + super(message); + // TODO Auto-generated constructor stub + } + + public ManagedException(Throwable cause) { + super(cause); + // TODO Auto-generated constructor stub + } + + public ManagedException(String message, Throwable cause) { + super(message, cause); + // TODO Auto-generated constructor stub + } + + public ManagedException(String message, Throwable cause, + boolean enableSuppression, boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + // TODO Auto-generated constructor stub + } + +} diff --git a/src/main/java/org/gcube/data/transfer/service/transfers/engine/faults/NotSupportedMethodException.java b/src/main/java/org/gcube/data/transfer/service/transfers/engine/faults/NotSupportedMethodException.java new file mode 100644 index 0000000..555aa7b --- /dev/null +++ b/src/main/java/org/gcube/data/transfer/service/transfers/engine/faults/NotSupportedMethodException.java @@ -0,0 +1,35 @@ +package org.gcube.data.transfer.service.transfers.engine.faults; + +public class NotSupportedMethodException extends Exception { + + /** + * + */ + private static final long serialVersionUID = 1L; + + public NotSupportedMethodException() { + // TODO Auto-generated constructor stub + } + + public NotSupportedMethodException(String message) { + super(message); + // TODO Auto-generated constructor stub + } + + public NotSupportedMethodException(Throwable cause) { + super(cause); + // TODO Auto-generated constructor stub + } + + public NotSupportedMethodException(String message, Throwable cause) { + super(message, cause); + // TODO Auto-generated constructor stub + } + + public NotSupportedMethodException(String message, Throwable cause, + boolean enableSuppression, boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + // TODO Auto-generated constructor stub + } + +} diff --git a/src/main/java/org/gcube/data/transfer/service/transfers/engine/faults/PluginExecutionException.java b/src/main/java/org/gcube/data/transfer/service/transfers/engine/faults/PluginExecutionException.java new file mode 100644 index 0000000..488c196 --- /dev/null +++ b/src/main/java/org/gcube/data/transfer/service/transfers/engine/faults/PluginExecutionException.java @@ -0,0 +1,35 @@ +package org.gcube.data.transfer.service.transfers.engine.faults; + +public class PluginExecutionException extends ManagedException { + + /** + * + */ + private static final long serialVersionUID = 2681096696757651730L; + + public PluginExecutionException() { + // TODO Auto-generated constructor stub + } + + public PluginExecutionException(String message) { + super(message); + // TODO Auto-generated constructor stub + } + + public PluginExecutionException(Throwable cause) { + super(cause); + // TODO Auto-generated constructor stub + } + + public PluginExecutionException(String message, Throwable cause) { + super(message, cause); + // TODO Auto-generated constructor stub + } + + public PluginExecutionException(String message, Throwable cause, boolean enableSuppression, + boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + // TODO Auto-generated constructor stub + } + +} diff --git a/src/main/java/org/gcube/data/transfer/service/transfers/engine/faults/PluginNotFoundException.java b/src/main/java/org/gcube/data/transfer/service/transfers/engine/faults/PluginNotFoundException.java new file mode 100644 index 0000000..9e65462 --- /dev/null +++ b/src/main/java/org/gcube/data/transfer/service/transfers/engine/faults/PluginNotFoundException.java @@ -0,0 +1,35 @@ +package org.gcube.data.transfer.service.transfers.engine.faults; + +public class PluginNotFoundException extends ManagedException { + + /** + * + */ + private static final long serialVersionUID = -5169583804790487322L; + + public PluginNotFoundException() { + // TODO Auto-generated constructor stub + } + + public PluginNotFoundException(String message) { + super(message); + // TODO Auto-generated constructor stub + } + + public PluginNotFoundException(Throwable cause) { + super(cause); + // TODO Auto-generated constructor stub + } + + public PluginNotFoundException(String message, Throwable cause) { + super(message, cause); + // TODO Auto-generated constructor stub + } + + public PluginNotFoundException(String message, Throwable cause, boolean enableSuppression, + boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + // TODO Auto-generated constructor stub + } + +} diff --git a/src/main/java/org/gcube/data/transfer/service/transfers/engine/faults/TicketNotFoundException.java b/src/main/java/org/gcube/data/transfer/service/transfers/engine/faults/TicketNotFoundException.java new file mode 100644 index 0000000..6e62aa2 --- /dev/null +++ b/src/main/java/org/gcube/data/transfer/service/transfers/engine/faults/TicketNotFoundException.java @@ -0,0 +1,36 @@ +package org.gcube.data.transfer.service.transfers.engine.faults; + +public class TicketNotFoundException extends Exception { + + /** + * + */ + private static final long serialVersionUID = -5761719004322780267L; + + public TicketNotFoundException() { + super(); + // TODO Auto-generated constructor stub + } + + public TicketNotFoundException(String message, Throwable cause, + boolean enableSuppression, boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + // TODO Auto-generated constructor stub + } + + public TicketNotFoundException(String message, Throwable cause) { + super(message, cause); + // TODO Auto-generated constructor stub + } + + public TicketNotFoundException(String message) { + super(message); + // TODO Auto-generated constructor stub + } + + public TicketNotFoundException(Throwable cause) { + super(cause); + // TODO Auto-generated constructor stub + } + +} diff --git a/src/main/java/org/gcube/data/transfer/service/transfers/engine/impl/AbstractTicketHandler.java b/src/main/java/org/gcube/data/transfer/service/transfers/engine/impl/AbstractTicketHandler.java new file mode 100644 index 0000000..fbf1985 --- /dev/null +++ b/src/main/java/org/gcube/data/transfer/service/transfers/engine/impl/AbstractTicketHandler.java @@ -0,0 +1,194 @@ +package org.gcube.data.transfer.service.transfers.engine.impl; + +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.Map.Entry; + +import org.apache.commons.io.FileUtils; +import org.apache.commons.io.IOUtils; +import org.gcube.data.transfer.model.PluginInvocation; +import org.gcube.data.transfer.model.TransferTicket; +import org.gcube.data.transfer.model.TransferTicket.Status; +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; +import org.gcube.data.transfer.service.transfers.engine.PersistenceProvider; +import org.gcube.data.transfer.service.transfers.engine.PluginManager; +import org.gcube.data.transfer.service.transfers.engine.faults.ManagedException; +import org.gcube.data.transfer.service.transfers.engine.faults.NotSupportedMethodException; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public abstract class AbstractTicketHandler { + + private TransferTicket ticket; + + PersistenceProvider persistenceProvider; + PluginManager pluginManager; + + + public AbstractTicketHandler(PersistenceProvider persProv,PluginManager plugMan, TransferTicket ticket) { + this.persistenceProvider=persProv; + this.pluginManager=plugMan; + this.ticket=ticket; + } + + protected void onStep(String msg,double progress,Status status,long transferredBytes){ + ticket.setStatus(status); + ticket.setMessage(msg); + ticket.setPercent(progress); + ticket.setTransferredBytes(transferredBytes); + try{ + long elapsedTime=System.currentTimeMillis()-ticket.getSubmissionTime().getValue().getTimeInMillis(); + long average=(transferredBytes/((elapsedTime==0?1:elapsedTime)))*1000; + ticket.setAverageTransferSpeed(average); + }catch(Exception e){ + log.warn("Unable to evaluate average ",e); + } + } + protected void onError(String message){ + onStep(message,ticket.getPercent(),Status.ERROR); + } + + protected void onStep(String msg,double progress,Status status){ + onStep(msg,progress,status,ticket.getTransferredBytes()); + } + + public TransferTicket getTicket(){ + return ticket; + } + + + + public void handle(){ + + InputStream is=null; + BufferedOutputStream out=null; + Boolean completedTransfer=false; + File destination=null; + + try{ + if(ticket.getSettings().getOptions().getMethod().equals(TransferMethod.DirectTransfer)) + throw new NotSupportedMethodException("Unable to manage request [ID "+ticket.getId()+"]. Method not supported : "+ticket.getSettings().getOptions().getMethod()); + + + log.trace("Request handling started. Ticket is "+ticket); + + onStep("Checking destination",0d,Status.TRANSFERRING,0l); + destination =persistenceProvider.prepareDestination(ticket.getDestinationSettings()); + ticket.setDestinationFileName(destination.getAbsolutePath()); + onStep("Opening input stream",0d,Status.TRANSFERRING,0l); + + + is=getInputStream(); + + + try{ + out=new BufferedOutputStream(new FileOutputStream(destination)); + } catch (IOException e) { + log.warn("Unable to create destination file.",e); + throw new ManagedException("Cannot save file in host"); + } + + transferStream(is, out); + completedTransfer=true; + // IF TRANSFER FAILS, EXCEPTIONS AR THROWN + + + + //Plugin execution + if(ticket.getPluginInvocations()!=null){ + for(PluginInvocation invocation:ticket.getPluginInvocations()){ + log.debug("Execution {}",invocation); + if(invocation.getParameters().containsValue(PluginInvocation.DESTINATION_FILE_PATH)){ + log.debug("Checking for param value : "+PluginInvocation.DESTINATION_FILE_PATH); + for(Entry param:invocation.getParameters().entrySet()) + if(param.getValue().equals(PluginInvocation.DESTINATION_FILE_PATH)){ + log.debug("Setting {} = {} ",param.getKey(),ticket.getDestinationFileName()); + param.setValue(ticket.getDestinationFileName()); + } + + } + onStep("Executing invocation "+invocation.getPluginId(),1d,Status.PLUGIN_EXECUTION); + pluginManager.execute(invocation); + } + } + + + onStep("Completed transfer",1d,Status.SUCCESS); + }catch(NotSupportedMethodException e){ + onError(e.getMessage()); + }catch(ManagedException e){ + onError(e.getMessage()); + }catch(Throwable t){ + onError("Unexpected error while downloading : "+t.getMessage()); + log.error("Unexpected error occurred",t); + }finally{ + log.debug("Finalizing transfer, ticket ID {} ",ticket.getId()); + if(out!=null)IOUtils.closeQuietly(out); + if(is!=null)IOUtils.closeQuietly(is); + + if((!completedTransfer)&& (destination!=null) && (destination.exists())) { + log.debug("Removing incomplete transfer.."); + try{ + FileUtils.forceDelete(destination); + }catch(Exception e){ + log.warn("Unable to clean {} ",destination); + } + } + + } + } + + + private void transferStream(InputStream in, OutputStream out) throws ManagedException{ + + long receivedTotal=0l; + + try{ + byte[] internalBuf=new byte[1024]; + int received=0; + while ((received=in.read(internalBuf))!=-1){ + out.write(internalBuf,0,received); + receivedTotal+=received; + onStep("Transferring",0d,Status.TRANSFERRING,receivedTotal); + } + out.flush(); + }catch(IOException e){ + log.debug("Unable to read from source",e); + throw new ManagedException("Unable to read from source."); + } + log.debug("Completed transfer phase for ticket ID {}. Transferred {} bytes. ",ticket.getId(),receivedTotal); + } + + private InputStream getInputStream() throws ManagedException{ + switch(ticket.getSettings().getOptions().getMethod()){ + case HTTPDownload:{ + try{ + HttpDownloadSettings options=(HttpDownloadSettings) (ticket.getSettings()); + return new BufferedInputStream(options.getSource().openStream()); + }catch(Exception e){ + log.debug("Unable to open connection ",e); + throw new ManagedException("Cannot open connection to source"); + } + } + case FileUpload :{ + try{ + FileUploadSettings options=(FileUploadSettings) (ticket.getSettings()); + return new BufferedInputStream(options.getPassedStream()); + }catch(Exception e){ + log.debug("Unable to open connection ",e); + throw new ManagedException("Cannot open connection to source"); + } + } + default: + throw new ManagedException(ticket.getSettings().getOptions().getMethod()+" cannot be managed"); + } + } +} diff --git a/src/main/java/org/gcube/data/transfer/service/transfers/engine/impl/CapabilitiesProviderImpl.java b/src/main/java/org/gcube/data/transfer/service/transfers/engine/impl/CapabilitiesProviderImpl.java new file mode 100644 index 0000000..e154e88 --- /dev/null +++ b/src/main/java/org/gcube/data/transfer/service/transfers/engine/impl/CapabilitiesProviderImpl.java @@ -0,0 +1,102 @@ +package org.gcube.data.transfer.service.transfers.engine.impl; + +import java.util.HashSet; + +import javax.inject.Inject; +import javax.inject.Singleton; + +import org.gcube.common.resources.gcore.GCoreEndpoint; +import org.gcube.data.transfer.model.PluginDescription; +import org.gcube.data.transfer.model.TransferCapabilities; +import org.gcube.data.transfer.model.options.HttpDownloadOptions; +import org.gcube.data.transfer.model.options.TransferOptions; +import org.gcube.data.transfer.service.transfers.engine.CapabilitiesProvider; +import org.gcube.data.transfer.service.transfers.engine.PersistenceProvider; +import org.gcube.data.transfer.service.transfers.engine.PluginManager; +import org.gcube.smartgears.ContextProvider; +import org.gcube.smartgears.configuration.container.ContainerConfiguration; +import org.gcube.smartgears.context.application.ApplicationContext; + +import lombok.Synchronized; + + +@Singleton +public class CapabilitiesProviderImpl implements CapabilitiesProvider { + + + + private TransferCapabilities capabilities=null; + + private PersistenceProvider persistenceProvider; + private PluginManager pluginManager; + + + @Inject + public CapabilitiesProviderImpl(PersistenceProvider persistenceProvider,PluginManager pluginManager) { + this.persistenceProvider = persistenceProvider; + this.pluginManager=pluginManager; + } + + @Override @Synchronized + public TransferCapabilities get() { + if(capabilities==null)capabilities=getCapabilities(); + return capabilities; + } + + private TransferCapabilities getCapabilities(){ + ApplicationContext context=ContextProvider.get(); + ContainerConfiguration configuration=context.container().configuration(); + + String hostName=configuration.hostname(); + String id=context.profile(GCoreEndpoint.class).id(); + Integer port=configuration.port(); + + HashSet meansOfTransfer=new HashSet(); + meansOfTransfer.add(HttpDownloadOptions.DEFAULT); + + + HashSet plugins=new HashSet(pluginManager.getInstalledPlugins().values()); + + + return new TransferCapabilities(id,hostName,port,meansOfTransfer,plugins,persistenceProvider.getAvaileblContextIds()); + } + +// private static String getHostname() throws Exception { +// String OS = System.getProperty("os.name").toLowerCase(); +// log.debug("Getting hostname.."); +// String hostName=null; +// if (OS.indexOf("win") >= 0) { +// log.debug("Detected windows.."); +// hostName=System.getenv("COMPUTERNAME"); +// if(hostName==null || hostName.equals("")){ +// log.debug("System env not found, trying via hostname command.."); +// hostName=execReadToString("hostname"); +// } +// } else +// if (OS.indexOf("nix") >= 0 || OS.indexOf("nux") >= 0) { +// log.debug("Detected linux.."); +// hostName= System.getenv("HOSTNAME"); +// if(hostName==null || hostName.equals("")){ +// log.debug("System env not found, trying via hostname command.."); +// hostName=execReadToString("hostname -f"); +// } +// if(hostName==null || hostName.equals("")){ +// log.debug("Hostname command didn't work, trying via hostname file.."); +// hostName=execReadToString("cat /etc/hostname"); +// } +// }else throw new Exception("OS not detected"); +// return hostName; +// } + + + +// public static String execReadToString(String execCommand) throws IOException { +// Process proc = Runtime.getRuntime().exec(execCommand); +// try (InputStream stream = proc.getInputStream()) { +// try (Scanner s = new Scanner(stream).useDelimiter("\\A")) { +// return s.hasNext() ? s.next() : ""; +// } +// } +// } + +} diff --git a/src/main/java/org/gcube/data/transfer/service/transfers/engine/impl/LocalRequestHandler.java b/src/main/java/org/gcube/data/transfer/service/transfers/engine/impl/LocalRequestHandler.java new file mode 100644 index 0000000..2fd5222 --- /dev/null +++ b/src/main/java/org/gcube/data/transfer/service/transfers/engine/impl/LocalRequestHandler.java @@ -0,0 +1,31 @@ +package org.gcube.data.transfer.service.transfers.engine.impl; + +import javax.ws.rs.WebApplicationException; +import javax.ws.rs.core.Response.Status; + +import org.gcube.data.transfer.model.TransferTicket; +import org.gcube.data.transfer.service.transfers.engine.PersistenceProvider; +import org.gcube.data.transfer.service.transfers.engine.PluginManager; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class LocalRequestHandler extends AbstractTicketHandler{ + + public LocalRequestHandler(PersistenceProvider persProv, PluginManager plugMan, TransferTicket ticket) { + super(persProv, plugMan, ticket); + } + + @Override + protected void onStep(String msg, double progress, org.gcube.data.transfer.model.TransferTicket.Status status, + long transferredBytes) { + super.onStep(msg, progress, status, transferredBytes); + log.trace("Stepping upload. Relative Ticket {} ",getTicket()); + } + + @Override + protected void onError(String message) { + log.error("Unable to manage upload request ticket {} MSG {} ",getTicket(),message); + throw new WebApplicationException("Internal ERROR "+message,Status.INTERNAL_SERVER_ERROR); + } +} diff --git a/src/main/java/org/gcube/data/transfer/service/transfers/engine/impl/PersistenceProviderImpl.java b/src/main/java/org/gcube/data/transfer/service/transfers/engine/impl/PersistenceProviderImpl.java new file mode 100644 index 0000000..8571fbb --- /dev/null +++ b/src/main/java/org/gcube/data/transfer/service/transfers/engine/impl/PersistenceProviderImpl.java @@ -0,0 +1,137 @@ +package org.gcube.data.transfer.service.transfers.engine.impl; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.HashSet; +import java.util.Set; + +import javax.inject.Singleton; + +import org.gcube.data.transfer.model.Destination; +import org.gcube.data.transfer.model.DestinationClashPolicy; +import org.gcube.data.transfer.service.transfers.engine.PersistenceProvider; +import org.gcube.data.transfer.service.transfers.engine.faults.DestinationAccessException; +import org.gcube.smartgears.ContextProvider; +import org.gcube.smartgears.configuration.application.ApplicationConfiguration; +import org.gcube.smartgears.context.application.ApplicationContext; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@Singleton +public class PersistenceProviderImpl implements PersistenceProvider { + + + + @Override + public File getPersistenceFolderById(String persistenceId) throws DestinationAccessException { + File toReturn=null; + log.debug("looking for persistence ID : {}",persistenceId); + + if(persistenceId.equalsIgnoreCase(Destination.DEFAULT_PERSISTENCE_ID)){ + log.debug("Persistence ID is default"); + ApplicationContext context=ContextProvider.get(); + toReturn=new File(context.persistence().location()); + }else{ + for(ApplicationConfiguration config:ContextProvider.get().container().configuration().apps()){ + if(config.context().equals(persistenceId)){ + log.debug("Found persistence ID {}",persistenceId); + toReturn= new File(config.persistence().location()); + break; + } + } + } + if(toReturn== null) throw new DestinationAccessException("Persistence ID "+persistenceId+" not found."); + if(!toReturn.exists()) throw new DestinationAccessException("Persistence ID "+persistenceId+", location "+toReturn.getAbsolutePath()+" location doesn't exists."); + if(!toReturn.canWrite()) throw new DestinationAccessException("Cannot write to Persistence ID "+persistenceId+", location "+toReturn.getAbsolutePath()+" ."); + if(!toReturn.isDirectory()) throw new DestinationAccessException("Persistence ID "+persistenceId+", location "+toReturn.getAbsolutePath()+" is a directory."); + if(!toReturn.canWrite()) throw new DestinationAccessException("Cannot write to Persistence ID "+persistenceId+", location "+toReturn.getAbsolutePath()+" ."); + return toReturn; + + } + + + @Override + public Set getAvaileblContextIds() { + HashSet toReturn=new HashSet<>(); + for(ApplicationConfiguration config:ContextProvider.get().container().configuration().apps()){ + String toAddID=config.context(); + if(toAddID.startsWith("/")) toAddID=toAddID.substring(1); + toReturn.add(toAddID); + } + return toReturn; + } + + @Override + public File prepareDestination(Destination dest) throws DestinationAccessException{ + File persistenceFolder=getPersistenceFolderById(dest.getPersistenceId()); + if(!persistenceFolder.canWrite()) throw new DestinationAccessException("Cannot write to selecte persistenceFolder [ID :"+dest.getPersistenceId()+"]"); + log.debug("Got Persistence folder ID {}, PATH {}",persistenceFolder.getAbsolutePath(),dest.getPersistenceId()); + String subFolderName=dest.getSubFolder(); + File subFolder=persistenceFolder; + if(subFolderName!=null){ + log.debug("Looking for subFolder : "+subFolder); + if(subFolderName.startsWith(File.pathSeparator)) throw new DestinationAccessException("SubFolder cannot be absolute."); + // String[] pathItems=subFolderName.split(File.pathSeparator); + // for(String subPath:pathItems){ + //// Set existingFiles=new HashSet(Arrays.asList(subFolder.list())); + // subFolder=new File(subFolder,subPath); + // if(subFolder.exists()){ + // if(!subFolder.canRead()) throw new DestinationAccessException("Cannot write to "+subFolder.getAbsolutePath()); + // }else if(dest.getCreateSubfolders()) subFolder.mkdir(); + // else throw new DestinationAccessException("Destination subfolder {} not found. Set createSubFolder=true to create intermediary directories."); + // } + + subFolder=new File(persistenceFolder,subFolderName); + if(subFolder.exists()){ + if(!subFolder.canRead()) throw new DestinationAccessException("Cannot write to "+subFolder.getAbsolutePath()); + manageClash(dest.getOnExistingSubFolder(),subFolder); + }else if(dest.getCreateSubfolders()) subFolder.mkdirs(); + else throw new DestinationAccessException("SubFolder not found. Use createSubFolders=true to create it."); + } + + File destination=new File(subFolder,dest.getDestinationFileName()); + if(destination.exists()) return manageClash(dest.getOnExistingFileName(),destination); + else { + try{ + destination.createNewFile(); + return destination; + }catch(IOException e){ + throw new DestinationAccessException("Unable to create file ",e); + } + } + } + + private static final File manageClash(DestinationClashPolicy policy, File clashing ) throws DestinationAccessException{ + log.debug("Managing clash for {}, policy is {} ",clashing.getAbsolutePath(),policy); + boolean dir=clashing.isDirectory(); + try{ + switch(policy){ + case ADD_SUFFIX : { + String clashingBaseName=clashing.getName(); + + int counter=1; + while(clashing.exists()){ + clashing=new File(clashing.getParentFile(),clashingBaseName+"("+counter+")"); + counter++; + } + if(dir)clashing.mkdirs(); + else clashing.createNewFile(); + break; + } + case FAIL: throw new DestinationAccessException("Found existing "+clashing.getAbsolutePath()+"policy is "+policy); + case REWRITE : { + Files.deleteIfExists(Paths.get(clashing.getAbsolutePath())); + if(dir)clashing.mkdirs(); + else clashing.createNewFile(); + break; + } + } + }catch(IOException e){ + throw new DestinationAccessException("Unable to rewrite existing destination",e); + } + return clashing; + } +} diff --git a/src/main/java/org/gcube/data/transfer/service/transfers/engine/impl/PluginManagerImpl.java b/src/main/java/org/gcube/data/transfer/service/transfers/engine/impl/PluginManagerImpl.java new file mode 100644 index 0000000..5bf332b --- /dev/null +++ b/src/main/java/org/gcube/data/transfer/service/transfers/engine/impl/PluginManagerImpl.java @@ -0,0 +1,84 @@ +package org.gcube.data.transfer.service.transfers.engine.impl; + +import java.util.HashMap; +import java.util.Map; +import java.util.ServiceLoader; + +import javax.inject.Singleton; + +import org.gcube.data.transfer.model.PluginDescription; +import org.gcube.data.transfer.model.PluginInvocation; +import org.gcube.data.transfer.plugin.AbstractPlugin; +import org.gcube.data.transfer.plugin.AbstractPluginFactory; +import org.gcube.data.transfer.plugin.ExecutionReport; +import org.gcube.data.transfer.plugin.fails.PluginException; +import org.gcube.data.transfer.service.transfers.engine.PluginManager; +import org.gcube.data.transfer.service.transfers.engine.faults.PluginExecutionException; +import org.gcube.data.transfer.service.transfers.engine.faults.PluginNotFoundException; + +import lombok.Synchronized; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@Singleton +public class PluginManagerImpl implements PluginManager { + + private static ServiceLoader abstractFactoryLoader = null; + + private static Map installedPlugins=null; + + + static{ + abstractFactoryLoader=ServiceLoader.load(AbstractPluginFactory.class); + + + + } + + @Override + public Map getInstalledPlugins() { + return init(); + } + + + @Synchronized + private static Map init() { + if(installedPlugins==null){ + Map toSet=new HashMap(); + log.trace("Loading plugins descriptors.."); + for(AbstractPluginFactory factory:abstractFactoryLoader){ + log.debug("loading {}, {} ",factory.getID(),factory.getDescription()); + toSet.put(factory.getID(), new PluginDescription(factory.getID(), factory.getDescription(), factory.getParameters())); + } + installedPlugins=toSet; + } + + return installedPlugins; + } + + @Override + public ExecutionReport execute(PluginInvocation invocation) + throws PluginNotFoundException, PluginExecutionException { + log.debug("Executing invocation {} ",invocation); + + AbstractPluginFactory factory=getFactory(invocation.getPluginId()); + log.debug("Loaded factory {} ",factory.getClass()); + log.debug("Checkign invocation .. "); + try{ + factory.checkInvocation(invocation); + AbstractPlugin plugin=factory.createWorker(invocation); + return plugin.execute(); + }catch(PluginException e){ + throw new PluginExecutionException(e.getMessage(),e); + } + } + + + private AbstractPluginFactory getFactory(String pluginId) throws PluginNotFoundException{ + for(AbstractPluginFactory factory:abstractFactoryLoader){ + if(factory.getID().equals(pluginId)) return factory; + } + throw new PluginNotFoundException("Plugin with ID "+pluginId+" not found"); + } + +} diff --git a/src/main/java/org/gcube/data/transfer/service/transfers/engine/impl/RequestHandler.java b/src/main/java/org/gcube/data/transfer/service/transfers/engine/impl/RequestHandler.java new file mode 100644 index 0000000..bb89a34 --- /dev/null +++ b/src/main/java/org/gcube/data/transfer/service/transfers/engine/impl/RequestHandler.java @@ -0,0 +1,32 @@ +package org.gcube.data.transfer.service.transfers.engine.impl; + +import org.gcube.data.transfer.model.TransferTicket; +import org.gcube.data.transfer.model.TransferTicket.Status; +import org.gcube.data.transfer.service.transfers.engine.PersistenceProvider; +import org.gcube.data.transfer.service.transfers.engine.PluginManager; +import org.gcube.data.transfer.service.transfers.engine.TicketManager; + +public class RequestHandler extends AbstractTicketHandler implements Runnable { + + + TicketManager ticketManager; + + @Override + public void run() { + handle(); + } + + + public RequestHandler(TicketManager ticketManager,TransferTicket ticket,PersistenceProvider persProv, PluginManager plugMan) { + super(persProv, plugMan,ticket); + this.ticketManager=ticketManager; + ticketManager.insertUpdate(ticket); + } + + @Override + protected void onStep(String msg, double progress, Status status, long transferredBytes) { + super.onStep(msg, progress, status,transferredBytes); + ticketManager.insertUpdate(getTicket()); + } + +} diff --git a/src/main/java/org/gcube/data/transfer/service/transfers/engine/impl/RequestManagerImpl.java b/src/main/java/org/gcube/data/transfer/service/transfers/engine/impl/RequestManagerImpl.java new file mode 100644 index 0000000..b98f482 --- /dev/null +++ b/src/main/java/org/gcube/data/transfer/service/transfers/engine/impl/RequestManagerImpl.java @@ -0,0 +1,76 @@ +package org.gcube.data.transfer.service.transfers.engine.impl; + +import java.util.UUID; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; + +import javax.inject.Inject; +import javax.inject.Singleton; + +import org.gcube.data.transfer.model.TransferRequest; +import org.gcube.data.transfer.model.TransferTicket; +import org.gcube.data.transfer.model.options.TransferOptions.TransferMethod; +import org.gcube.data.transfer.service.transfers.engine.PersistenceProvider; +import org.gcube.data.transfer.service.transfers.engine.PluginManager; +import org.gcube.data.transfer.service.transfers.engine.RequestManager; +import org.gcube.data.transfer.service.transfers.engine.TicketManager; + +import lombok.extern.slf4j.Slf4j; + +@Singleton +@Slf4j +public class RequestManagerImpl implements RequestManager{ + + ExecutorService executor; + + TicketManager ticketManager; + PersistenceProvider persistenceProvider; + PluginManager pluginManager; + + + + @Inject + public RequestManagerImpl(TicketManager ticketManager,PersistenceProvider persistenceProvider,PluginManager pluginManager) { + executor=Executors.newCachedThreadPool(); + this.persistenceProvider=persistenceProvider; + this.pluginManager=pluginManager; + this.ticketManager=ticketManager; + } + + + + @Override + public TransferTicket put(TransferRequest request) { + request.setId(UUID.randomUUID().toString()); + log.info("Managing request {} ",request); + TransferTicket toReturn=new TransferTicket(request); + + if(request.getSettings().getOptions().getMethod().equals(TransferMethod.FileUpload)){ + log.debug("Request is sync"); + new LocalRequestHandler(persistenceProvider, pluginManager, toReturn).handle(); + return toReturn; + }else{ + log.debug("Request is async"); + executor.execute(new RequestHandler(ticketManager,new TransferTicket(request),persistenceProvider,pluginManager)); + return toReturn; + } + } + +@Override +public void shutdown() { + log.debug("Calling shutdown.."); + executor.shutdownNow(); + + long timeout=4; + TimeUnit unit=TimeUnit.SECONDS; + + log.debug("Waiting termination.. {} {} ",timeout,unit); + boolean halted=false; + try { + halted=executor.awaitTermination(timeout, unit); + } catch (InterruptedException e) { + log.debug("Halted threads : {} ",halted); + } +} +} diff --git a/src/main/java/org/gcube/data/transfer/service/transfers/engine/impl/TransferTicketManagerImpl.java b/src/main/java/org/gcube/data/transfer/service/transfers/engine/impl/TransferTicketManagerImpl.java new file mode 100644 index 0000000..02605fe --- /dev/null +++ b/src/main/java/org/gcube/data/transfer/service/transfers/engine/impl/TransferTicketManagerImpl.java @@ -0,0 +1,98 @@ +package org.gcube.data.transfer.service.transfers.engine.impl; + +import java.util.Map.Entry; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; + +import javax.inject.Singleton; + +import lombok.extern.slf4j.Slf4j; + +import org.gcube.data.transfer.model.TransferTicket; +import org.gcube.data.transfer.service.transfers.engine.TicketManager; +import org.gcube.data.transfer.service.transfers.engine.faults.TicketNotFoundException; + +@Slf4j +@Singleton +public class TransferTicketManagerImpl implements TicketManager{ + + private static ConcurrentHashMap theMap=new ConcurrentHashMap<>(); + private static final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1); + + static{ + scheduler.scheduleAtFixedRate(new Runnable() { + + private static final long TTL =30*60*1000; + + + @Override + public void run() { + log.debug("Running Ticket cleaner, TTL is "+TTL); + int removed=0; + for(Entry entry:theMap.entrySet()) + if(System.currentTimeMillis()-entry.getValue().getLastUsageTime()>TTL){ + theMap.remove(entry.getKey()); + removed++; + } + log.debug("Removed "+removed+" old tickets"); + + } + }, 30, 30, TimeUnit.MINUTES); + } + + + public class TTLContainer { + + private long lastUsageTime=System.currentTimeMillis(); + private TransferTicket theTicket; + public TTLContainer(TransferTicket theTicket) { + this.theTicket = theTicket; + } + + + private void update(){ + lastUsageTime=System.currentTimeMillis(); + } + + public TransferTicket getTicket(){ + update(); + return theTicket; + } + + public long getLastUsageTime() { + return lastUsageTime; + } + + } + + + @Override + public boolean insertUpdate(TransferTicket toInsert) { + return (theMap.put(toInsert.getId(), new TTLContainer(toInsert))!=null); + } + + @Override + public TransferTicket get(String ticketId) throws TicketNotFoundException { + if(theMap.containsKey(ticketId))return theMap.get(ticketId).getTicket(); + else throw new TicketNotFoundException(String.format("Ticket [%s] not found. Request is probably served and outdated",ticketId)); + } + + + @Override + public void shutdown() { + scheduler.shutdownNow(); + + long timeout=4; + TimeUnit unit=TimeUnit.SECONDS; + + log.debug("Waiting termination.. {} {} ",timeout,unit); + boolean halted=false; + try { + halted=scheduler.awaitTermination(timeout, unit); + } catch (InterruptedException e) { + log.debug("Halted threads : {} ",halted); + } + } +} diff --git a/src/main/resources/META-INF/beans.xml b/src/main/resources/META-INF/beans.xml new file mode 100644 index 0000000..14bded4 --- /dev/null +++ b/src/main/resources/META-INF/beans.xml @@ -0,0 +1,5 @@ + + \ No newline at end of file diff --git a/src/main/webapp/WEB-INF/LICENSE b/src/main/webapp/WEB-INF/LICENSE new file mode 100644 index 0000000..b3c3804 --- /dev/null +++ b/src/main/webapp/WEB-INF/LICENSE @@ -0,0 +1,313 @@ +European Union Public Licence V. 1.1 + + +EUPL © the European Community 2007 + + +This European Union Public Licence (the “EUPL”) applies to the Work or Software +(as defined below) which is provided under the terms of this Licence. Any use of +the Work, other than as authorised under this Licence is prohibited (to the +extent such use is covered by a right of the copyright holder of the Work). + +The Original Work is provided under the terms of this Licence when the Licensor +(as defined below) has placed the following notice immediately following the +copyright notice for the Original Work: + +Licensed under the EUPL V.1.1 + +or has expressed by any other mean his willingness to license under the EUPL. + + + +1. Definitions + +In this Licence, the following terms have the following meaning: + +- The Licence: this Licence. + +- The Original Work or the Software: the software distributed and/or + communicated by the Licensor under this Licence, available as Source Code and + also as Executable Code as the case may be. + +- Derivative Works: the works or software that could be created by the Licensee, + based upon the Original Work or modifications thereof. This Licence does not + define the extent of modification or dependence on the Original Work required + in order to classify a work as a Derivative Work; this extent is determined by + copyright law applicable in the country mentioned in Article 15. + +- The Work: the Original Work and/or its Derivative Works. + +- The Source Code: the human-readable form of the Work which is the most + convenient for people to study and modify. + +- The Executable Code: any code which has generally been compiled and which is + meant to be interpreted by a computer as a program. + +- The Licensor: the natural or legal person that distributes and/or communicates + the Work under the Licence. + +- Contributor(s): any natural or legal person who modifies the Work under the + Licence, or otherwise contributes to the creation of a Derivative Work. + +- The Licensee or “You”: any natural or legal person who makes any usage of the + Software under the terms of the Licence. + +- Distribution and/or Communication: any act of selling, giving, lending, + renting, distributing, communicating, transmitting, or otherwise making + available, on-line or off-line, copies of the Work or providing access to its + essential functionalities at the disposal of any other natural or legal + person. + + + +2. Scope of the rights granted by the Licence + +The Licensor hereby grants You a world-wide, royalty-free, non-exclusive, +sub-licensable licence to do the following, for the duration of copyright vested +in the Original Work: + +- use the Work in any circumstance and for all usage, reproduce the Work, modify +- the Original Work, and make Derivative Works based upon the Work, communicate +- to the public, including the right to make available or display the Work or +- copies thereof to the public and perform publicly, as the case may be, the +- Work, distribute the Work or copies thereof, lend and rent the Work or copies +- thereof, sub-license rights in the Work or copies thereof. + +Those rights can be exercised on any media, supports and formats, whether now +known or later invented, as far as the applicable law permits so. + +In the countries where moral rights apply, the Licensor waives his right to +exercise his moral right to the extent allowed by law in order to make effective +the licence of the economic rights here above listed. + +The Licensor grants to the Licensee royalty-free, non exclusive usage rights to +any patents held by the Licensor, to the extent necessary to make use of the +rights granted on the Work under this Licence. + + + +3. Communication of the Source Code + +The Licensor may provide the Work either in its Source Code form, or as +Executable Code. If the Work is provided as Executable Code, the Licensor +provides in addition a machine-readable copy of the Source Code of the Work +along with each copy of the Work that the Licensor distributes or indicates, in +a notice following the copyright notice attached to the Work, a repository where +the Source Code is easily and freely accessible for as long as the Licensor +continues to distribute and/or communicate the Work. + + + +4. Limitations on copyright + +Nothing in this Licence is intended to deprive the Licensee of the benefits from +any exception or limitation to the exclusive rights of the rights owners in the +Original Work or Software, of the exhaustion of those rights or of other +applicable limitations thereto. + + + +5. Obligations of the Licensee + +The grant of the rights mentioned above is subject to some restrictions and +obligations imposed on the Licensee. Those obligations are the following: + +Attribution right: the Licensee shall keep intact all copyright, patent or +trademarks notices and all notices that refer to the Licence and to the +disclaimer of warranties. The Licensee must include a copy of such notices and a +copy of the Licence with every copy of the Work he/she distributes and/or +communicates. The Licensee must cause any Derivative Work to carry prominent +notices stating that the Work has been modified and the date of modification. + +Copyleft clause: If the Licensee distributes and/or communicates copies of the +Original Works or Derivative Works based upon the Original Work, this +Distribution and/or Communication will be done under the terms of this Licence +or of a later version of this Licence unless the Original Work is expressly +distributed only under this version of the Licence. The Licensee (becoming +Licensor) cannot offer or impose any additional terms or conditions on the Work +or Derivative Work that alter or restrict the terms of the Licence. + +Compatibility clause: If the Licensee Distributes and/or Communicates Derivative +Works or copies thereof based upon both the Original Work and another work +licensed under a Compatible Licence, this Distribution and/or Communication can +be done under the terms of this Compatible Licence. For the sake of this clause, +“Compatible Licence” refers to the licences listed in the appendix attached to +this Licence. Should the Licensee’s obligations under the Compatible Licence +conflict with his/her obligations under this Licence, the obligations of the +Compatible Licence shall prevail. + +Provision of Source Code: When distributing and/or communicating copies of the +Work, the Licensee will provide a machine-readable copy of the Source Code or +indicate a repository where this Source will be easily and freely available for +as long as the Licensee continues to distribute and/or communicate the Work. + +Legal Protection: This Licence does not grant permission to use the trade names, +trademarks, service marks, or names of the Licensor, except as required for +reasonable and customary use in describing the origin of the Work and +reproducing the content of the copyright notice. + + + +6. Chain of Authorship + +The original Licensor warrants that the copyright in the Original Work granted +hereunder is owned by him/her or licensed to him/her and that he/she has the +power and authority to grant the Licence. + +Each Contributor warrants that the copyright in the modifications he/she brings +to the Work are owned by him/her or licensed to him/her and that he/she has the +power and authority to grant the Licence. + +Each time You accept the Licence, the original Licensor and subsequent +Contributors grant You a licence to their contributions to the Work, under the +terms of this Licence. + + + +7. Disclaimer of Warranty + +The Work is a work in progress, which is continuously improved by numerous +contributors. It is not a finished work and may therefore contain defects or +“bugs” inherent to this type of software development. + +For the above reason, the Work is provided under the Licence on an “as is” basis +and without warranties of any kind concerning the Work, including without +limitation merchantability, fitness for a particular purpose, absence of defects +or errors, accuracy, non-infringement of intellectual property rights other than +copyright as stated in Article 6 of this Licence. + +This disclaimer of warranty is an essential part of the Licence and a condition +for the grant of any rights to the Work. + + + +8. Disclaimer of Liability + +Except in the cases of wilful misconduct or damages directly caused to natural +persons, the Licensor will in no event be liable for any direct or indirect, +material or moral, damages of any kind, arising out of the Licence or of the use +of the Work, including without limitation, damages for loss of goodwill, work +stoppage, computer failure or malfunction, loss of data or any commercial +damage, even if the Licensor has been advised of the possibility of such +damage. However, the Licensor will be liable under statutory product liability +laws as far such laws apply to the Work. + + + +9. Additional agreements + +While distributing the Original Work or Derivative Works, You may choose to +conclude an additional agreement to offer, and charge a fee for, acceptance of +support, warranty, indemnity, or other liability obligations and/or services +consistent with this Licence. However, in accepting such obligations, You may +act only on your own behalf and on your sole responsibility, not on behalf of +the original Licensor or any other Contributor, and only if You agree to +indemnify, defend, and hold each Contributor harmless for any liability incurred +by, or claims asserted against such Contributor by the fact You have accepted +any such warranty or additional liability. + + + +10. Acceptance of the Licence + +The provisions of this Licence can be accepted by clicking on an icon “I agree” +placed under the bottom of a window displaying the text of this Licence or by +affirming consent in any other similar way, in accordance with the rules of +applicable law. Clicking on that icon indicates your clear and irrevocable +acceptance of this Licence and all of its terms and conditions. + +Similarly, you irrevocably accept this Licence and all of its terms and +conditions by exercising any rights granted to You by Article 2 of this Licence, +such as the use of the Work, the creation by You of a Derivative Work or the +Distribution and/or Communication by You of the Work or copies thereof. + + + +11. Information to the public + +In case of any Distribution and/or Communication of the Work by means of +electronic communication by You (for example, by offering to download the Work +from a remote location) the distribution channel or media (for example, a +website) must at least provide to the public the information requested by the +applicable law regarding the Licensor, the Licence and the way it may be +accessible, concluded, stored and reproduced by the Licensee. + + + +12. Termination of the Licence + +The Licence and the rights granted hereunder will terminate automatically upon +any breach by the Licensee of the terms of the Licence. + +Such a termination will not terminate the licences of any person who has +received the Work from the Licensee under the Licence, provided such persons +remain in full compliance with the Licence. + + + +13. Miscellaneous + +Without prejudice of Article 9 above, the Licence represents the complete +agreement between the Parties as to the Work licensed hereunder. + +If any provision of the Licence is invalid or unenforceable under applicable +law, this will not affect the validity or enforceability of the Licence as a +whole. Such provision will be construed and/or reformed so as necessary to make +it valid and enforceable. + +The European Commission may publish other linguistic versions and/or new +versions of this Licence, so far this is required and reasonable, without +reducing the scope of the rights granted by the Licence. New versions of the +Licence will be published with a unique version number. + +All linguistic versions of this Licence, approved by the European Commission, +have identical value. Parties can take advantage of the linguistic version of +their choice. + + + +14. Jurisdiction + +Any litigation resulting from the interpretation of this License, arising +between the European Commission, as a Licensor, and any Licensee, will be +subject to the jurisdiction of the Court of Justice of the European Communities, +as laid down in article 238 of the Treaty establishing the European Community. + +Any litigation arising between Parties, other than the European Commission, and +resulting from the interpretation of this License, will be subject to the +exclusive jurisdiction of the competent court where the Licensor resides or +conducts its primary business. + + + +15. Applicable Law + +This Licence shall be governed by the law of the European Union country where +the Licensor resides or has his registered office. + +This licence shall be governed by the Belgian law if: + +- a litigation arises between the European Commission, as a Licensor, and any +- Licensee; the Licensor, other than the European Commission, has no residence +- or registered office inside a European Union country. + + +=== + + +Appendix + + + +“Compatible Licences” according to article 5 EUPL are: + + +- GNU General Public License (GNU GPL) v. 2 + +- Open Software License (OSL) v. 2.1, v. 3.0 + +- Common Public License v. 1.0 + +- Eclipse Public License v. 1.0 + +- Cecill v. 2.0 \ No newline at end of file diff --git a/src/main/webapp/WEB-INF/README b/src/main/webapp/WEB-INF/README new file mode 100644 index 0000000..8ccf802 --- /dev/null +++ b/src/main/webapp/WEB-INF/README @@ -0,0 +1,78 @@ +The gCube System - DataTransferService +-------------------------------------------------- + +Service used to receive data from other hosting nodes + + +This software is part of the gCube Framework (https://www.gcube-system.org/): an +open-source software toolkit used for building and operating Hybrid Data +Infrastructures enabling the dynamic deployment of Virtual Research Environments +by favouring the realisation of reuse oriented policies. + +The projects leading to this software have received funding from a series of +European Union programmes including: +* the Sixth Framework Programme for Research and Technological Development - +DILIGENT (grant no. 004260); +* the Seventh Framework Programme for research, technological development and +demonstration - D4Science (grant no. 212488), D4Science-II (grant no. +239019),ENVRI (grant no. 283465), EUBrazilOpenBio (grant no. 288754), iMarine +(grant no. 283644); +* the H2020 research and innovation programme - BlueBRIDGE (grant no. 675680), +EGIEngage (grant no. 654142), ENVRIplus (grant no. 654182), Parthenos (grant +no. 654119), SoBigData (grant no. 654024); + + +Version +-------------------------------------------------- + +2.0.0-SNAPSHOT (2017-05-17) + +Please see the file named "changelog.xml" in this directory for the release notes. + + + +Authors +-------------------------------------------------- + +* Fabio Sinibaldi (fabio.sinibaldi-AT-isti.cnr.it) Istituto di Scienza e Tecnologie dell'Informazione "A. Faedo" - CNR, Pisa (Italy). + +Maintainers +----------- + +* Fabio Sinibaldi (fabio.sinibaldi-AT-isti.cnr.it) Istituto di Scienza e Tecnologie dell'Informazione "A. Faedo" - CNR, Pisa (Italy). + + +Download information +-------------------------------------------------- + +Source code is available from SVN: + https://svn.d4science.research-infrastructures.eu/gcube/trunk/data-transfer/data-transfer-service + +Binaries can be downloaded from the gCube website: + https://www.gcube-system.org/ + +Installation +-------------------------------------------------- + +Installation documentation is available on-line in the gCube Wiki: + https://wiki.gcube-system.org/gcube/index.php/Data_Transfer_2 + +Documentation +-------------------------------------------------- + +Documentation is available on-line in the gCube Wiki: + https://wiki.gcube-system.org/gcube/index.php/Data_Transfer_2 + https://wiki.gcube-system.org/gcube/index.php/How_to_use_Data_Transfer_2 + + +Support +-------------------------------------------------- + +Bugs and support requests can be reported in the gCube issue tracking tool: + https://support.d4science.org/projects/gcube/ + + +Licensing +-------------------------------------------------- + +This software is licensed under the terms you may find in the file named "LICENSE" in this directory. \ No newline at end of file diff --git a/src/main/webapp/WEB-INF/changelog.xml b/src/main/webapp/WEB-INF/changelog.xml new file mode 100644 index 0000000..01ec4cf --- /dev/null +++ b/src/main/webapp/WEB-INF/changelog.xml @@ -0,0 +1,13 @@ + + + First Release + + + Added Destination + Added Plugin + + + Improved plugin management + Endorsed decompress-plugin + + \ No newline at end of file diff --git a/src/main/webapp/WEB-INF/descriptor.xml b/src/main/webapp/WEB-INF/descriptor.xml new file mode 100644 index 0000000..1ce8afc --- /dev/null +++ b/src/main/webapp/WEB-INF/descriptor.xml @@ -0,0 +1,30 @@ + + servicearchive + + tar.gz + + / + + + /home/fabio/workspaces/trunk_workspace/data-transfer-service/distro + / + true + + README + LICENSE + changelog.xml + + 755 + true + + + + + target/data-transfer-service.war + /data-transfer-service + + + \ No newline at end of file diff --git a/src/main/webapp/WEB-INF/gcube-app.xml b/src/main/webapp/WEB-INF/gcube-app.xml new file mode 100644 index 0000000..5a8c80d --- /dev/null +++ b/src/main/webapp/WEB-INF/gcube-app.xml @@ -0,0 +1,11 @@ + + data-transfer-service + DataTransfer + 2.0.0-SNAPSHOT + Data Tansfer Service + + + + diff --git a/src/main/webapp/WEB-INF/profile.xml b/src/main/webapp/WEB-INF/profile.xml new file mode 100644 index 0000000..9e39e15 --- /dev/null +++ b/src/main/webapp/WEB-INF/profile.xml @@ -0,0 +1,27 @@ + + + + Service + + Service used to receive data from other hosting nodes + DataTransfer + data-transfer-service + 1.0.0 + + + data-transfer-service + 2.0.0-SNAPSHOT + + org.gcube.data.transfer + data-transfer-service + 2.0.0-SNAPSHOT + + + data-transfer-service.jar + + + + + + + diff --git a/src/main/webapp/WEB-INF/web.xml b/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 0000000..0cd9080 --- /dev/null +++ b/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,22 @@ + + + + + + org.gcube.data.transfer.service.DTService + org.glassfish.jersey.servlet.ServletContainer + + javax.ws.rs.Application + org.gcube.data.transfer.service.DTService + + + jersey.config.server.provider.classnames + org.glassfish.jersey.media.multipart.MultiPartFeature + + 1 + + + org.gcube.data.transfer.service.DTService + /gcube/service/* + + \ No newline at end of file diff --git a/src/test/java/org/gcube/data/transfer/service/ logback-test.xml b/src/test/java/org/gcube/data/transfer/service/ logback-test.xml new file mode 100644 index 0000000..b70dd26 --- /dev/null +++ b/src/test/java/org/gcube/data/transfer/service/ logback-test.xml @@ -0,0 +1,14 @@ + + + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + + + \ No newline at end of file diff --git a/src/test/java/org/gcube/data/transfer/service/CapabilitiesProviderFactory.java b/src/test/java/org/gcube/data/transfer/service/CapabilitiesProviderFactory.java new file mode 100644 index 0000000..8eba760 --- /dev/null +++ b/src/test/java/org/gcube/data/transfer/service/CapabilitiesProviderFactory.java @@ -0,0 +1,34 @@ +package org.gcube.data.transfer.service; + +import java.util.Collections; +import java.util.HashSet; + +import org.gcube.data.transfer.model.PluginDescription; +import org.gcube.data.transfer.model.TransferCapabilities; +import org.gcube.data.transfer.model.options.HttpDownloadOptions; +import org.gcube.data.transfer.model.options.TransferOptions; +import org.gcube.data.transfer.service.transfers.engine.CapabilitiesProvider; +import org.gcube.data.transfer.service.transfers.engine.impl.PluginManagerImpl; +import org.glassfish.hk2.api.Factory; + +public class CapabilitiesProviderFactory implements Factory { + + @Override + public void dispose(CapabilitiesProvider instance) { + + } + + @Override + public CapabilitiesProvider provide() { + return new CapabilitiesProvider(){ + @Override + public TransferCapabilities get() { + return new TransferCapabilities("12345", "localhost", 80, + Collections.singleton((TransferOptions)HttpDownloadOptions.DEFAULT), + new HashSet(new PluginManagerImpl().getInstalledPlugins().values()) + ,Collections. emptySet()); + } + }; + } + +} diff --git a/src/test/java/org/gcube/data/transfer/service/ClashPolicyTest.java b/src/test/java/org/gcube/data/transfer/service/ClashPolicyTest.java new file mode 100644 index 0000000..b3c97b8 --- /dev/null +++ b/src/test/java/org/gcube/data/transfer/service/ClashPolicyTest.java @@ -0,0 +1,16 @@ +package org.gcube.data.transfer.service; + +import java.io.File; + +import org.gcube.data.transfer.service.transfers.engine.faults.DestinationAccessException; + +public class ClashPolicyTest { + + public static void main(String[] args) throws DestinationAccessException { + File dir=new File ("/home/fabio/workspaces/DT_TESTS"); + dir.mkdirs(); +// System.out.println(RequestHandler.manageClash(DestinationClashPolicy.ADD_SUFFIX, new File(dir,"clashing.file")).getAbsolutePath()); + + } + +} diff --git a/src/test/java/org/gcube/data/transfer/service/DebugExceptionMapper.java b/src/test/java/org/gcube/data/transfer/service/DebugExceptionMapper.java new file mode 100644 index 0000000..5545704 --- /dev/null +++ b/src/test/java/org/gcube/data/transfer/service/DebugExceptionMapper.java @@ -0,0 +1,21 @@ +package org.gcube.data.transfer.service; + +import javax.ws.rs.WebApplicationException; +import javax.ws.rs.core.Response; +import javax.ws.rs.ext.ExceptionMapper; +import javax.ws.rs.ext.Provider; + +@Provider +public class DebugExceptionMapper implements ExceptionMapper { + + @Override + public Response toResponse(Exception exception) { + exception.printStackTrace(); + Response toReturn=null; + if(exception instanceof WebApplicationException) + toReturn=((WebApplicationException)exception).getResponse(); + else + toReturn=Response.serverError().entity(exception.getMessage()).build(); + return toReturn; + } +} diff --git a/src/test/java/org/gcube/data/transfer/service/PersistenceProviderFactory.java b/src/test/java/org/gcube/data/transfer/service/PersistenceProviderFactory.java new file mode 100644 index 0000000..4eded89 --- /dev/null +++ b/src/test/java/org/gcube/data/transfer/service/PersistenceProviderFactory.java @@ -0,0 +1,45 @@ +package org.gcube.data.transfer.service; + +import java.io.File; +import java.io.IOException; +import java.util.Collections; +import java.util.Set; + +import org.gcube.data.transfer.model.Destination; +import org.gcube.data.transfer.service.transfers.engine.PersistenceProvider; +import org.gcube.data.transfer.service.transfers.engine.faults.DestinationAccessException; +import org.glassfish.hk2.api.Factory; + +class PersistenceProviderFactory implements Factory{ + + @Override + public PersistenceProvider provide() { + return new PersistenceProvider() { + + @Override + public File getPersistenceFolderById(String persistenceId) throws DestinationAccessException { + return new File(System.getProperty("java.io.tmpdir")); + } + + @Override + public Set getAvaileblContextIds() { + return Collections.emptySet(); + } + + @Override + public File prepareDestination(Destination dest) throws DestinationAccessException { + try { + return File.createTempFile("dest", ""); + } catch (IOException e) { + return null; + } + } + }; + } + + @Override + public void dispose(PersistenceProvider arg0) { + // TODO Auto-generated method stub + + } +} diff --git a/src/test/java/org/gcube/data/transfer/service/PluginManagerFactory.java b/src/test/java/org/gcube/data/transfer/service/PluginManagerFactory.java new file mode 100644 index 0000000..6be4772 --- /dev/null +++ b/src/test/java/org/gcube/data/transfer/service/PluginManagerFactory.java @@ -0,0 +1,23 @@ +package org.gcube.data.transfer.service; + +import org.gcube.data.transfer.service.transfers.engine.PluginManager; +import org.gcube.data.transfer.service.transfers.engine.impl.PluginManagerImpl; +import org.glassfish.hk2.api.Factory; + +public class PluginManagerFactory implements Factory { + + static PluginManagerImpl impl=new PluginManagerImpl(); + + + @Override + public void dispose(PluginManager arg0) { + // TODO Auto-generated method stub + + } + + @Override + public PluginManager provide() { + return impl; + } + +} diff --git a/src/test/java/org/gcube/data/transfer/service/RequestManagerFactory.java b/src/test/java/org/gcube/data/transfer/service/RequestManagerFactory.java new file mode 100644 index 0000000..953f255 --- /dev/null +++ b/src/test/java/org/gcube/data/transfer/service/RequestManagerFactory.java @@ -0,0 +1,21 @@ +package org.gcube.data.transfer.service; + +import org.gcube.data.transfer.service.transfers.engine.RequestManager; +import org.gcube.data.transfer.service.transfers.engine.impl.RequestManagerImpl; +import org.glassfish.hk2.api.Factory; + +public class RequestManagerFactory implements Factory { + + @Override + public void dispose(RequestManager instance) { + + } + + @Override + public RequestManager provide() { + return new RequestManagerImpl(new TicketManagerProvider().provide(), + new PersistenceProviderFactory().provide(), + new PluginManagerFactory().provide()); + } + +} diff --git a/src/test/java/org/gcube/data/transfer/service/TestCall.java b/src/test/java/org/gcube/data/transfer/service/TestCall.java new file mode 100644 index 0000000..1352ae9 --- /dev/null +++ b/src/test/java/org/gcube/data/transfer/service/TestCall.java @@ -0,0 +1,132 @@ +package org.gcube.data.transfer.service; + +import java.io.File; +import java.net.MalformedURLException; +import java.net.URL; + +import javax.ws.rs.NotFoundException; +import javax.ws.rs.client.Entity; +import javax.ws.rs.client.WebTarget; +import javax.ws.rs.core.Application; +import javax.ws.rs.core.MediaType; + +import org.gcube.data.transfer.model.Destination; +import org.gcube.data.transfer.model.ServiceConstants; +import org.gcube.data.transfer.model.TransferCapabilities; +import org.gcube.data.transfer.model.TransferRequest; +import org.gcube.data.transfer.model.TransferTicket; +import org.gcube.data.transfer.model.TransferTicket.Status; +import org.gcube.data.transfer.model.options.HttpDownloadOptions; +import org.gcube.data.transfer.model.settings.HttpDownloadSettings; +import org.gcube.data.transfer.service.transfers.Capabilities; +import org.gcube.data.transfer.service.transfers.engine.CapabilitiesProvider; +import org.gcube.data.transfer.service.transfers.engine.PersistenceProvider; +import org.gcube.data.transfer.service.transfers.engine.PluginManager; +import org.gcube.data.transfer.service.transfers.engine.RequestManager; +import org.gcube.data.transfer.service.transfers.engine.TicketManager; +import org.glassfish.hk2.utilities.binding.AbstractBinder; +import org.glassfish.jersey.client.ClientConfig; +import org.glassfish.jersey.media.multipart.FormDataMultiPart; +import org.glassfish.jersey.media.multipart.MultiPartFeature; +import org.glassfish.jersey.media.multipart.file.FileDataBodyPart; +import org.glassfish.jersey.server.ResourceConfig; +import org.glassfish.jersey.test.JerseyTest; +import org.junit.Assert; +import org.junit.Test; + + +public class TestCall extends JerseyTest { + + public static class MyBinder extends AbstractBinder{ + + public MyBinder() { + super(); + // TODO Auto-generated constructor stub + } + + @Override + protected void configure() { + bindFactory(TicketManagerProvider.class).to(TicketManager.class); + bindFactory(CapabilitiesProviderFactory.class).to(CapabilitiesProvider.class); + bindFactory(RequestManagerFactory.class).to(RequestManager.class); + bindFactory(PersistenceProviderFactory.class).to(PersistenceProvider.class); + bindFactory(PluginManagerFactory.class).to(PluginManager.class); + + } + } + + + @Override + protected Application configure() { + System.out.println("Configuration for "+ServiceConstants.APPLICATION_PATH); + + ResourceConfig config= new ResourceConfig(Capabilities.class,ProviderLoggingListener.class); + config.register(new MyBinder()); + config.register(DebugExceptionMapper.class); + + + //Multipart + config.packages("org.glassfish.jersey.media.multipart"); + config.packages("org.gcube.data.transfer.service.transfers"); + config.register(MultiPartFeature.class); + return config; + } + + + @Override + protected void configureClient(ClientConfig config) { + // TODO Auto-generated method stub + super.configureClient(config); + config.register(MultiPartFeature.class); + } + + @Test + public void capabilities(){ + WebTarget target=target(ServiceConstants.CAPABILTIES_SERVLET_NAME); + System.err.println(target.getUri()); + System.out.println(target.request(MediaType.APPLICATION_JSON).get(TransferCapabilities.class)); + } + + @Test(expected=NotFoundException.class) + public void testTicketNotFound(){ + System.out.println(getTicketById("myVeryLongestId")); + } + + @Test + public void transfer() throws MalformedURLException{ + TransferRequest request=new TransferRequest("", new HttpDownloadSettings(new URL("http://data.d4science.org/bm1sRTg0Y1ZZZHRraUZuNG1IUGdvOUVFMnlOcTlFRmlHbWJQNStIS0N6Yz0"), HttpDownloadOptions.DEFAULT),new Destination("something")); + TransferTicket submissionResponse=submit(request); + System.out.println("Obtained "+submissionResponse); + boolean continuePolling=true; + do{ + TransferTicket ticket=getTicketById(submissionResponse.getId()); + System.out.println("Status : "+ticket); + continuePolling=ticket.getStatus().equals(Status.PENDING)||ticket.getStatus().equals(Status.TRANSFERRING)||ticket.getStatus().equals(Status.WAITING); + try{ + Thread.sleep(1000); + }catch(InterruptedException e){} + }while(continuePolling); + } + + @Test + public void RESTUpload(){ + FormDataMultiPart multipart = new FormDataMultiPart(); + File toSend=new File("/home/fabio/life@dev2.d4science.org"); + Assert.assertTrue(toSend!=null); + Assert.assertTrue(toSend.exists()); + multipart.bodyPart(new FileDataBodyPart(ServiceConstants.MULTIPART_FILE, toSend)); + WebTarget target=target(ServiceConstants.REST_SERVLET_NAME).path(ServiceConstants.REST_FILE_UPLOAD).path("data-transfer-service").path("my/sub/path"); + + + System.out.println(target.request().post(Entity.entity(multipart, multipart.getMediaType()))); + } + + + private TransferTicket getTicketById(String id){ + return target(ServiceConstants.STATUS_SERVLET_NAME).path(id).request(MediaType.APPLICATION_JSON).get(TransferTicket.class); + } + + private TransferTicket submit(TransferRequest req){ + return target(ServiceConstants.REQUESTS_SERVLET_NAME).request(MediaType.APPLICATION_JSON).post(Entity.entity(req,MediaType.APPLICATION_JSON),TransferTicket.class); + } +} diff --git a/src/test/java/org/gcube/data/transfer/service/TestPlugins.java b/src/test/java/org/gcube/data/transfer/service/TestPlugins.java new file mode 100644 index 0000000..fa947e6 --- /dev/null +++ b/src/test/java/org/gcube/data/transfer/service/TestPlugins.java @@ -0,0 +1,20 @@ +package org.gcube.data.transfer.service; + +import java.util.Map; + +import org.gcube.data.transfer.model.PluginDescription; +import org.gcube.data.transfer.service.transfers.engine.impl.PluginManagerImpl; +import org.junit.Assert; +import org.junit.Test; + +public class TestPlugins { + + @Test + public void testPlugins(){ + Map plugins=new PluginManagerImpl().getInstalledPlugins(); + Assert.assertNotNull(plugins); + System.out.println(plugins); + } + + +} diff --git a/src/test/java/org/gcube/data/transfer/service/TicketManagerProvider.java b/src/test/java/org/gcube/data/transfer/service/TicketManagerProvider.java new file mode 100644 index 0000000..76df8c3 --- /dev/null +++ b/src/test/java/org/gcube/data/transfer/service/TicketManagerProvider.java @@ -0,0 +1,41 @@ +package org.gcube.data.transfer.service; + +import java.net.MalformedURLException; +import java.net.URL; +import java.util.UUID; + +import org.gcube.data.transfer.model.TransferRequest; +import org.gcube.data.transfer.model.TransferTicket; +import org.gcube.data.transfer.model.options.HttpDownloadOptions; +import org.gcube.data.transfer.model.settings.HttpDownloadSettings; +import org.gcube.data.transfer.model.utils.DateWrapper; +import org.gcube.data.transfer.service.transfers.engine.TicketManager; +import org.gcube.data.transfer.service.transfers.engine.faults.TicketNotFoundException; +import org.gcube.data.transfer.service.transfers.engine.impl.TransferTicketManagerImpl; +import org.glassfish.hk2.api.Factory; + +public class TicketManagerProvider implements Factory { + + + @Override + public void dispose(TicketManager instance) { + + } + + @Override + public TicketManager provide() { + return new TransferTicketManagerImpl(){ +// @Override +// public TransferTicket get(String ticketId) +// throws TicketNotFoundException{ +// URL url=null; +// try{ +// url=new URL("http://some.where.com"); +// }catch(MalformedURLException e){} +// TransferRequest request=new TransferRequest(UUID.randomUUID().toString(), new HttpDownloadSettings(url,new HttpDownloadOptions())); +// return new TransferTicket(request, org.gcube.data.transfer.model.TransferTicket.Status.STOPPED, 1005467l, .57d, 123345, new DateWrapper(),"/dev/null","bona"); +//// throw new TicketNotFoundException(); +// } + }; + } +} diff --git a/src/test/resources/logback.xml b/src/test/resources/logback.xml new file mode 100644 index 0000000..b70dd26 --- /dev/null +++ b/src/test/resources/logback.xml @@ -0,0 +1,14 @@ + + + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + + + \ No newline at end of file