diff --git a/.classpath b/.classpath
new file mode 100644
index 0000000..e43402f
--- /dev/null
+++ b/.classpath
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/.project b/.project
new file mode 100644
index 0000000..cdb05cd
--- /dev/null
+++ b/.project
@@ -0,0 +1,23 @@
+
+
+ data-transfer-library
+
+
+
+
+
+ org.eclipse.jdt.core.javabuilder
+
+
+
+
+ org.eclipse.m2e.core.maven2Builder
+
+
+
+
+
+ org.eclipse.jdt.core.javanature
+ org.eclipse.m2e.core.maven2Nature
+
+
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..ec4300d
--- /dev/null
+++ b/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,5 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7
+org.eclipse.jdt.core.compiler.compliance=1.7
+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/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..9ac47a3
--- /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}/Tabular_Data_Manager
+
+Documentation
+--------------------------------------------------
+
+Documentation is available on-line in the gCube Wiki:
+ ${gcube.wikiRoot}/Tabular_Data_Manager
+ ${gcube.wikiRoot}/Tabular_Data_Manager
+
+
+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..993d50e
--- /dev/null
+++ b/distro/changelog.xml
@@ -0,0 +1,5 @@
+
+
+ First Release
+
+
\ 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
+
+
+
+
+
+ /${artifactId}
+
+
+
\ No newline at end of file
diff --git a/distro/profile.xml b/distro/profile.xml
new file mode 100644
index 0000000..429a22e
--- /dev/null
+++ b/distro/profile.xml
@@ -0,0 +1,29 @@
+
+
+
+ Service
+
+ ${description}
+ DataTransfer
+ ${artifactId}
+ 1.0.0
+
+
+ ${description}
+ ${artifactId}
+ ${version}
+
+ ${groupId}
+ ${artifactId}
+ ${version}
+
+ library
+
+ ${build.finalName}.jar
+
+
+
+
+
+
+
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..40447fa
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,38 @@
+
+ 4.0.0
+
+ org.gcube.tools
+ maven-parent
+ LATEST
+
+ org.gcube.data.transfer
+ data-transfer-library
+ 0.0.1-SNAPSHOT
+ DataTransfer-library
+
+
+
+ org.gcube.data.transfer
+ data-transfer-model
+ 1.0.0-SNAPSHOT
+
+
+ junit
+ junit
+ 4.10
+ test
+
+
+
+
+ org.projectlombok
+ lombok
+ 0.11.6
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main/java/org/gcube/data/transfer/library/CapabilitiesManager.java b/src/main/java/org/gcube/data/transfer/library/CapabilitiesManager.java
new file mode 100644
index 0000000..81a2387
--- /dev/null
+++ b/src/main/java/org/gcube/data/transfer/library/CapabilitiesManager.java
@@ -0,0 +1,70 @@
+package org.gcube.data.transfer.library;
+
+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 lombok.extern.slf4j.Slf4j;
+
+import org.gcube.data.transfer.model.TransferCapabilities;
+
+@Slf4j
+public class CapabilitiesManager {
+
+ 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 TransferCapabilities theObject;
+ public TTLContainer(TransferCapabilities theObject) {
+ this.theObject = theObject;
+ }
+
+
+ private void update(){
+ lastUsageTime=System.currentTimeMillis();
+ }
+
+ public TransferCapabilities getTicket(){
+ update();
+ return theObject;
+ }
+
+ public long getLastUsageTime() {
+ return lastUsageTime;
+ }
+
+ }
+
+
+ public static TransferCapabilities get(String hostname){
+
+ }
+}
diff --git a/src/main/java/org/gcube/data/transfer/library/TransferResult.java b/src/main/java/org/gcube/data/transfer/library/TransferResult.java
new file mode 100644
index 0000000..57fd3b8
--- /dev/null
+++ b/src/main/java/org/gcube/data/transfer/library/TransferResult.java
@@ -0,0 +1,5 @@
+package org.gcube.data.transfer.library;
+
+public class TransferResult {
+
+}
diff --git a/src/main/java/org/gcube/data/transfer/library/Transferer.java b/src/main/java/org/gcube/data/transfer/library/Transferer.java
new file mode 100644
index 0000000..4a5ec68
--- /dev/null
+++ b/src/main/java/org/gcube/data/transfer/library/Transferer.java
@@ -0,0 +1,55 @@
+package org.gcube.data.transfer.library;
+
+import java.io.File;
+import java.net.URL;
+
+import org.gcube.data.transfer.library.faults.InvalidSourceException;
+import org.gcube.data.transfer.library.faults.SourceNotSetException;
+import org.gcube.data.transfer.library.model.Source;
+
+
+public abstract class Transferer {
+
+
+
+
+ protected Source source=null;
+
+
+ public Transferer localFile(File f){
+
+ }
+
+ public Transferer localFile(String path){
+
+ }
+
+ public Transferer storageFileId(String fileId){
+
+ }
+
+ public Transferer fromURL(URL sourceURL){
+
+ }
+
+
+ public TransferResult transfer() throws SourceNotSetException, InvalidSourceException{
+ checkSource();
+ source.prepare();
+ TransferResult result=doTheTransfer();
+ source.clean();
+ return result;
+ }
+
+
+ protected void checkSource() throws SourceNotSetException, InvalidSourceException{
+ if(source==null) throw new SourceNotSetException();
+ source.validate();
+ }
+
+ protected abstract TransferResult doTheTransfer();
+
+
+
+
+}
diff --git a/src/main/java/org/gcube/data/transfer/library/TransfererBuilder.java b/src/main/java/org/gcube/data/transfer/library/TransfererBuilder.java
new file mode 100644
index 0000000..44d279c
--- /dev/null
+++ b/src/main/java/org/gcube/data/transfer/library/TransfererBuilder.java
@@ -0,0 +1,24 @@
+package org.gcube.data.transfer.library;
+
+import org.gcube.data.transfer.library.faults.HostingNodeNotFoundException;
+import org.gcube.data.transfer.library.faults.ServiceNotFoundException;
+import org.gcube.data.transfer.library.faults.UnreachableNodeException;
+
+public class TransfererBuilder {
+
+ public Transferer getTransfererByHost(String host) throws UnreachableNodeException, ServiceNotFoundException{
+ // Check reachable host
+ // Check DTS presence
+ // get capabilities
+ // return transferer by capabilities
+ }
+ public Transferer getTransfererByhostingNodeId(String hostId) throws HostingNodeNotFoundException, UnreachableNodeException, ServiceNotFoundException{
+ String hostname=retrieveHostnameByNodeId(hostId);
+ return getTransfererByHost(hostname);
+ }
+
+
+ private String retrieveHostnameByNodeId(String nodeId)throws HostingNodeNotFoundException{
+
+ }
+}
diff --git a/src/main/java/org/gcube/data/transfer/library/faults/DataTransferException.java b/src/main/java/org/gcube/data/transfer/library/faults/DataTransferException.java
new file mode 100644
index 0000000..069e3e9
--- /dev/null
+++ b/src/main/java/org/gcube/data/transfer/library/faults/DataTransferException.java
@@ -0,0 +1,35 @@
+package org.gcube.data.transfer.library.faults;
+
+public abstract class DataTransferException extends Exception {
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 8488351139669552406L;
+
+ public DataTransferException() {
+ // TODO Auto-generated constructor stub
+ }
+
+ public DataTransferException(String message) {
+ super(message);
+ // TODO Auto-generated constructor stub
+ }
+
+ public DataTransferException(Throwable cause) {
+ super(cause);
+ // TODO Auto-generated constructor stub
+ }
+
+ public DataTransferException(String message, Throwable cause) {
+ super(message, cause);
+ // TODO Auto-generated constructor stub
+ }
+
+ public DataTransferException(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/library/faults/HostingNodeNotFoundException.java b/src/main/java/org/gcube/data/transfer/library/faults/HostingNodeNotFoundException.java
new file mode 100644
index 0000000..8e547fa
--- /dev/null
+++ b/src/main/java/org/gcube/data/transfer/library/faults/HostingNodeNotFoundException.java
@@ -0,0 +1,35 @@
+package org.gcube.data.transfer.library.faults;
+
+public class HostingNodeNotFoundException extends InitializationException {
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 5786009015981659074L;
+
+ public HostingNodeNotFoundException() {
+ // TODO Auto-generated constructor stub
+ }
+
+ public HostingNodeNotFoundException(String message) {
+ super(message);
+ // TODO Auto-generated constructor stub
+ }
+
+ public HostingNodeNotFoundException(Throwable cause) {
+ super(cause);
+ // TODO Auto-generated constructor stub
+ }
+
+ public HostingNodeNotFoundException(String message, Throwable cause) {
+ super(message, cause);
+ // TODO Auto-generated constructor stub
+ }
+
+ public HostingNodeNotFoundException(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/library/faults/InitializationException.java b/src/main/java/org/gcube/data/transfer/library/faults/InitializationException.java
new file mode 100644
index 0000000..d074a9c
--- /dev/null
+++ b/src/main/java/org/gcube/data/transfer/library/faults/InitializationException.java
@@ -0,0 +1,35 @@
+package org.gcube.data.transfer.library.faults;
+
+public class InitializationException extends DataTransferException {
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 2204462227670167203L;
+
+ public InitializationException() {
+ // TODO Auto-generated constructor stub
+ }
+
+ public InitializationException(String message) {
+ super(message);
+ // TODO Auto-generated constructor stub
+ }
+
+ public InitializationException(Throwable cause) {
+ super(cause);
+ // TODO Auto-generated constructor stub
+ }
+
+ public InitializationException(String message, Throwable cause) {
+ super(message, cause);
+ // TODO Auto-generated constructor stub
+ }
+
+ public InitializationException(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/library/faults/InvalidSourceException.java b/src/main/java/org/gcube/data/transfer/library/faults/InvalidSourceException.java
new file mode 100644
index 0000000..93e7b09
--- /dev/null
+++ b/src/main/java/org/gcube/data/transfer/library/faults/InvalidSourceException.java
@@ -0,0 +1,35 @@
+package org.gcube.data.transfer.library.faults;
+
+public class InvalidSourceException extends DataTransferException {
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 7631518288856917202L;
+
+ public InvalidSourceException() {
+ // TODO Auto-generated constructor stub
+ }
+
+ public InvalidSourceException(String message) {
+ super(message);
+ // TODO Auto-generated constructor stub
+ }
+
+ public InvalidSourceException(Throwable cause) {
+ super(cause);
+ // TODO Auto-generated constructor stub
+ }
+
+ public InvalidSourceException(String message, Throwable cause) {
+ super(message, cause);
+ // TODO Auto-generated constructor stub
+ }
+
+ public InvalidSourceException(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/library/faults/ServiceNotFoundException.java b/src/main/java/org/gcube/data/transfer/library/faults/ServiceNotFoundException.java
new file mode 100644
index 0000000..adf0395
--- /dev/null
+++ b/src/main/java/org/gcube/data/transfer/library/faults/ServiceNotFoundException.java
@@ -0,0 +1,35 @@
+package org.gcube.data.transfer.library.faults;
+
+public class ServiceNotFoundException extends InitializationException {
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = -3494011839783891174L;
+
+ public ServiceNotFoundException() {
+ // TODO Auto-generated constructor stub
+ }
+
+ public ServiceNotFoundException(String message) {
+ super(message);
+ // TODO Auto-generated constructor stub
+ }
+
+ public ServiceNotFoundException(Throwable cause) {
+ super(cause);
+ // TODO Auto-generated constructor stub
+ }
+
+ public ServiceNotFoundException(String message, Throwable cause) {
+ super(message, cause);
+ // TODO Auto-generated constructor stub
+ }
+
+ public ServiceNotFoundException(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/library/faults/SourceNotSetException.java b/src/main/java/org/gcube/data/transfer/library/faults/SourceNotSetException.java
new file mode 100644
index 0000000..12733f4
--- /dev/null
+++ b/src/main/java/org/gcube/data/transfer/library/faults/SourceNotSetException.java
@@ -0,0 +1,35 @@
+package org.gcube.data.transfer.library.faults;
+
+public class SourceNotSetException extends DataTransferException {
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = -5868191252361823341L;
+
+ public SourceNotSetException() {
+ // TODO Auto-generated constructor stub
+ }
+
+ public SourceNotSetException(String message) {
+ super(message);
+ // TODO Auto-generated constructor stub
+ }
+
+ public SourceNotSetException(Throwable cause) {
+ super(cause);
+ // TODO Auto-generated constructor stub
+ }
+
+ public SourceNotSetException(String message, Throwable cause) {
+ super(message, cause);
+ // TODO Auto-generated constructor stub
+ }
+
+ public SourceNotSetException(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/library/faults/UnreachableNodeException.java b/src/main/java/org/gcube/data/transfer/library/faults/UnreachableNodeException.java
new file mode 100644
index 0000000..a01a338
--- /dev/null
+++ b/src/main/java/org/gcube/data/transfer/library/faults/UnreachableNodeException.java
@@ -0,0 +1,37 @@
+package org.gcube.data.transfer.library.faults;
+
+public class UnreachableNodeException extends InitializationException {
+
+
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 8739586712271226827L;
+
+ public UnreachableNodeException() {
+ // TODO Auto-generated constructor stub
+ }
+
+ public UnreachableNodeException(String message) {
+ super(message);
+ // TODO Auto-generated constructor stub
+ }
+
+ public UnreachableNodeException(Throwable cause) {
+ super(cause);
+ // TODO Auto-generated constructor stub
+ }
+
+ public UnreachableNodeException(String message, Throwable cause) {
+ super(message, cause);
+ // TODO Auto-generated constructor stub
+ }
+
+ public UnreachableNodeException(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/library/model/LocalSource.java b/src/main/java/org/gcube/data/transfer/library/model/LocalSource.java
new file mode 100644
index 0000000..0e9a93a
--- /dev/null
+++ b/src/main/java/org/gcube/data/transfer/library/model/LocalSource.java
@@ -0,0 +1,36 @@
+package org.gcube.data.transfer.library.model;
+
+import java.io.File;
+
+import org.gcube.data.transfer.library.faults.InvalidSourceException;
+
+public class LocalSource extends Source {
+
+ private File theFile=null;
+
+ public LocalSource(File theFile) {
+ super();
+ this.theFile = theFile;
+ }
+
+ @Override
+ public boolean validate() throws InvalidSourceException {
+ if(!theFile.exists()) throw new InvalidSourceException("File "+theFile.getAbsolutePath()+"doesn't exist");
+ if(!theFile.canRead()) throw new InvalidSourceException("Unable to read from file "+theFile.getAbsolutePath());
+ if(theFile.isDirectory()) throw new InvalidSourceException("Transfer of directory is not yet supported");
+ return true;
+ }
+
+ @Override
+ public void prepare() {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void clean() {
+ // TODO Auto-generated method stub
+
+ }
+
+}
diff --git a/src/main/java/org/gcube/data/transfer/library/model/Source.java b/src/main/java/org/gcube/data/transfer/library/model/Source.java
new file mode 100644
index 0000000..7d9d261
--- /dev/null
+++ b/src/main/java/org/gcube/data/transfer/library/model/Source.java
@@ -0,0 +1,19 @@
+package org.gcube.data.transfer.library.model;
+
+import org.gcube.data.transfer.library.faults.InvalidSourceException;
+
+import lombok.Data;
+
+@Data
+public abstract class Source{
+
+ public static enum SourceType{
+ URI,STORAGE_ID,LOCAL_FILE
+ }
+
+ public abstract boolean validate() throws InvalidSourceException;
+
+ public abstract void prepare();
+
+ public abstract void clean();
+}
\ No newline at end of file
diff --git a/src/main/java/org/gcube/data/transfer/library/model/URLSource.java b/src/main/java/org/gcube/data/transfer/library/model/URLSource.java
new file mode 100644
index 0000000..fd3caac
--- /dev/null
+++ b/src/main/java/org/gcube/data/transfer/library/model/URLSource.java
@@ -0,0 +1,59 @@
+package org.gcube.data.transfer.library.model;
+
+import java.net.HttpURLConnection;
+import java.net.URL;
+
+import org.gcube.data.transfer.library.faults.InvalidSourceException;
+
+public class URLSource extends Source {
+
+
+ private URL theURL=null;
+
+
+ public URLSource(URL theURL) {
+ super();
+ this.theURL = theURL;
+ }
+
+ @Override
+ public boolean validate() throws InvalidSourceException {
+ try{
+ HttpURLConnection conn=(HttpURLConnection) theURL.openConnection();
+ conn.setConnectTimeout(3);
+ conn.setRequestMethod("HEAD");
+ int responseCode = conn.getResponseCode();
+ return (200 <= responseCode && responseCode <= 399);
+ }catch(Exception e){
+ throw new InvalidSourceException("Unable to contact URL "+theURL,e);
+ }
+ }
+
+ @Override
+ public void prepare() {
+ // nothing to do
+
+ }
+
+ @Override
+ public void clean() {
+ // nothing to do
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Object#toString()
+ */
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder();
+ builder.append("URLSource [theURL=");
+ builder.append(theURL);
+ builder.append("]");
+ return builder.toString();
+ }
+
+ public URL getTheURL() {
+ return theURL;
+ }
+
+}
diff --git a/src/main/java/org/gcube/data/transfer/library/utils/Utils.java b/src/main/java/org/gcube/data/transfer/library/utils/Utils.java
new file mode 100644
index 0000000..26ca627
--- /dev/null
+++ b/src/main/java/org/gcube/data/transfer/library/utils/Utils.java
@@ -0,0 +1,33 @@
+package org.gcube.data.transfer.library.utils;
+
+import java.io.IOException;
+import java.net.HttpURLConnection;
+import java.net.URL;
+
+public class Utils {
+
+ /**
+ * Pings a HTTP URL. This effectively sends a HEAD request and returns true
if the response code is in
+ * the 200-399 range.
+ * @param url The HTTP URL to be pinged.
+ * @param timeout The timeout in millis for both the connection timeout and the response read timeout. Note that
+ * the total timeout is effectively two times the given timeout.
+ * @return true
if the given HTTP URL has returned response code 200-399 on a HEAD request within the
+ * given timeout, otherwise false
.
+ */
+ public static boolean pingURL(String url, int timeout) {
+ url = url.replaceFirst("^https", "http"); // Otherwise an exception may be thrown on invalid SSL certificates.
+
+ try {
+ HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection();
+ connection.setConnectTimeout(timeout);
+ connection.setReadTimeout(timeout);
+ connection.setRequestMethod("HEAD");
+ int responseCode = connection.getResponseCode();
+ return (200 <= responseCode && responseCode <= 399);
+ } catch (IOException exception) {
+ return false;
+ }
+ }
+
+}