git-svn-id: http://svn.research-infrastructures.eu/public/d4science/gcube/trunk/spatial-data/ws-thredds@167619 82a268e6-3cf1-43bd-a215-b396298e98cf
commit
4c09cfeb84
@ -0,0 +1,36 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry kind="src" output="target/classes" path="src/main/java">
|
||||
<attributes>
|
||||
<attribute name="optional" value="true"/>
|
||||
<attribute name="maven.pomderived" value="true"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry excluding="**" kind="src" output="target/classes" path="src/main/resources">
|
||||
<attributes>
|
||||
<attribute name="maven.pomderived" value="true"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="src" output="target/test-classes" path="src/test/java">
|
||||
<attributes>
|
||||
<attribute name="optional" value="true"/>
|
||||
<attribute name="maven.pomderived" value="true"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry excluding="**" kind="src" output="target/test-classes" path="src/test/resources">
|
||||
<attributes>
|
||||
<attribute name="maven.pomderived" value="true"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8">
|
||||
<attributes>
|
||||
<attribute name="maven.pomderived" value="true"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
|
||||
<attributes>
|
||||
<attribute name="maven.pomderived" value="true"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="output" path="target/classes"/>
|
||||
</classpath>
|
@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>ws-thredds</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.jdt.core.javabuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.m2e.core.maven2Builder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||
<nature>org.eclipse.m2e.core.maven2Nature</nature>
|
||||
</natures>
|
||||
</projectDescription>
|
@ -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/<project>=UTF-8
|
@ -0,0 +1,5 @@
|
||||
eclipse.preferences.version=1
|
||||
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
|
||||
org.eclipse.jdt.core.compiler.compliance=1.8
|
||||
org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
|
||||
org.eclipse.jdt.core.compiler.source=1.8
|
@ -0,0 +1,4 @@
|
||||
activeProfiles=
|
||||
eclipse.preferences.version=1
|
||||
resolveWorkspaceProjects=false
|
||||
version=1
|
@ -0,0 +1 @@
|
||||
${gcube.license}
|
@ -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.
|
@ -0,0 +1,8 @@
|
||||
<ReleaseNotes>
|
||||
<Changeset component="ws-thredds-0.0.1" date="2017-08-22">
|
||||
<Change>First Release</Change>
|
||||
</Changeset>
|
||||
<Changeset component="ws-thredds-0.0.2" date="2017-11-19">
|
||||
<Change>Cleanup folder fix</Change>
|
||||
</Changeset>
|
||||
</ReleaseNotes>
|
@ -0,0 +1,30 @@
|
||||
<assembly
|
||||
xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0 http://maven.apache.org/xsd/assembly-1.1.0.xsd">
|
||||
<id>servicearchive</id>
|
||||
<formats>
|
||||
<format>tar.gz</format>
|
||||
</formats>
|
||||
<baseDirectory>/</baseDirectory>
|
||||
<fileSets>
|
||||
<fileSet>
|
||||
<directory>${distroDirectory}</directory>
|
||||
<outputDirectory>/</outputDirectory>
|
||||
<useDefaultExcludes>true</useDefaultExcludes>
|
||||
<includes>
|
||||
<include>README</include>
|
||||
<include>LICENSE</include>
|
||||
<include>changelog.xml</include>
|
||||
</includes>
|
||||
<fileMode>755</fileMode>
|
||||
<filtered>true</filtered>
|
||||
</fileSet>
|
||||
</fileSets>
|
||||
<files>
|
||||
<file>
|
||||
<source>target/${build.finalName}.${project.packaging}</source>
|
||||
<outputDirectory>/${artifactId}</outputDirectory>
|
||||
</file>
|
||||
</files>
|
||||
</assembly>
|
@ -0,0 +1,29 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Resource>
|
||||
<ID></ID>
|
||||
<Type>Service</Type>
|
||||
<Profile>
|
||||
<Description>${description}</Description>
|
||||
<Class>Portlets</Class>
|
||||
<Name>${artifactId}</Name>
|
||||
<Version>1.0.0</Version>
|
||||
<Packages>
|
||||
<Software>
|
||||
<Description>${description}</Description>
|
||||
<Name>${artifactId}</Name>
|
||||
<Version>${version}</Version>
|
||||
<MavenCoordinates>
|
||||
<groupId>${groupId}</groupId>
|
||||
<artifactId>${artifactId}</artifactId>
|
||||
<version>${version}</version>
|
||||
</MavenCoordinates>
|
||||
<Type>library</Type>
|
||||
<Files>
|
||||
<File>${build.finalName}.jar</File>
|
||||
</Files>
|
||||
</Software>
|
||||
</Packages>
|
||||
</Profile>
|
||||
</Resource>
|
||||
|
||||
|
@ -0,0 +1,69 @@
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.gcube.tools</groupId>
|
||||
<artifactId>maven-parent</artifactId>
|
||||
<version>LATEST</version>
|
||||
</parent>
|
||||
<groupId>org.gcube.spatial-data</groupId>
|
||||
<artifactId>ws-thredds</artifactId>
|
||||
<version>0.2.0-SNAPSHOT</version>
|
||||
<name>ws-thredds</name>
|
||||
<description>prototype of WS integration with data-transfer for Thredds pubblication</description>
|
||||
|
||||
<properties>
|
||||
<distroDirectory>${project.basedir}/distro</distroDirectory>
|
||||
<svnBaseUrl>http://svn.research-infrastructures.eu/d4science/gcube/trunk/portlets/user/${project.artifactId}</svnBaseUrl>
|
||||
</properties>
|
||||
|
||||
|
||||
<scm>
|
||||
<connection>scm:svn:${svnBaseUrl}/${project.artifactId}</connection>
|
||||
<developerConnection>scm:svn:${svnBaseUrl}/${project.artifactId}</developerConnection>
|
||||
<url>${svnBaseUrl}/${project.artifactId}</url>
|
||||
</scm>
|
||||
|
||||
|
||||
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.gcube.spatial.data</groupId>
|
||||
<artifactId>sdi-library</artifactId>
|
||||
<version>[1.0.0-SNAPSHOT,2.0.0-SNAPSHOT)</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.gcube.data.transfer</groupId>
|
||||
<artifactId>data-transfer-library</artifactId>
|
||||
<version>[1.2.0-SNAPSHOT,2.0.0-SNAPSHOT)</version>
|
||||
</dependency>
|
||||
<!-- <dependency> -->
|
||||
<!-- <groupId>org.gcube.data.transfer</groupId> -->
|
||||
<!-- <artifactId>data-transfer-model</artifactId> -->
|
||||
<!-- <version>1.2.4-4.11.0-163203</version> -->
|
||||
<!-- </dependency> -->
|
||||
<dependency>
|
||||
<groupId>org.gcube.common</groupId>
|
||||
<artifactId>home-library-jcr</artifactId>
|
||||
<version>[2.0.0-SNAPSHOT,3.0.0-SNAPSHOT)</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.gcube.common</groupId>
|
||||
<artifactId>home-library</artifactId>
|
||||
<version>[2.0.0-SNAPSHOT,3.0.0-SNAPSHOT)</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-log4j12</artifactId>
|
||||
<version>1.6.4</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
|
||||
</dependencies>
|
||||
|
||||
</project>
|
@ -0,0 +1,162 @@
|
||||
package org.gcube.usecases.ws.thredds;
|
||||
|
||||
import static org.gcube.resources.discovery.icclient.ICFactory.clientFor;
|
||||
import static org.gcube.resources.discovery.icclient.ICFactory.queryFor;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.nio.file.Files;
|
||||
import java.text.SimpleDateFormat;
|
||||
|
||||
import javax.ws.rs.client.Client;
|
||||
import javax.ws.rs.client.ClientBuilder;
|
||||
import javax.ws.rs.client.WebTarget;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
|
||||
import org.apache.tika.io.IOUtils;
|
||||
import org.gcube.common.resources.gcore.GCoreEndpoint;
|
||||
import org.gcube.data.transfer.library.DataTransferClient;
|
||||
import org.gcube.data.transfer.library.client.AuthorizationFilter;
|
||||
import org.gcube.data.transfer.library.faults.ServiceNotFoundException;
|
||||
import org.gcube.data.transfer.library.faults.UnreachableNodeException;
|
||||
import org.gcube.data.transfer.model.Destination;
|
||||
import org.gcube.data.transfer.model.DestinationClashPolicy;
|
||||
import org.gcube.data.transfer.model.plugins.thredds.ThreddsInfo;
|
||||
import org.gcube.resources.discovery.client.api.DiscoveryClient;
|
||||
import org.gcube.resources.discovery.client.queries.api.SimpleQuery;
|
||||
import org.gcube.usecases.ws.thredds.faults.RemoteFileNotFoundException;
|
||||
import org.gcube.usecases.ws.thredds.faults.UnableToLockException;
|
||||
import org.glassfish.jersey.client.ClientConfig;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Slf4j
|
||||
public class Commons {
|
||||
|
||||
|
||||
|
||||
static final SimpleDateFormat DATE_FORMAT= new SimpleDateFormat("dd-MM-yy:HH:mm:SS");
|
||||
|
||||
|
||||
public static void cleanupFolder(String toCleanPath, String destinationToken) {
|
||||
String toRestoreToken=TokenSetter.getCurrentToken();
|
||||
try{
|
||||
log.debug("Setting target token {} for cleanup request of path {} ",destinationToken,toCleanPath);
|
||||
TokenSetter.setToken(destinationToken);
|
||||
String hostname=getThreddsHost();
|
||||
DataTransferClient client=getDTClient(hostname);
|
||||
File toTransfer=File.createTempFile("clean", ".dt_temp");
|
||||
toTransfer.createNewFile();
|
||||
Destination dest=new Destination();
|
||||
dest.setCreateSubfolders(true);
|
||||
dest.setOnExistingFileName(DestinationClashPolicy.REWRITE);
|
||||
dest.setOnExistingSubFolder(DestinationClashPolicy.REWRITE);
|
||||
dest.setPersistenceId("thredds");
|
||||
dest.setSubFolder("public/netcdf/"+toCleanPath);
|
||||
log.info("Going to cleanup remote folder {} on {} ",dest.getSubFolder(),hostname);
|
||||
client.localFile(toTransfer, dest);
|
||||
log.info("Done");
|
||||
}catch(Exception e) {
|
||||
log.error("Unable to delete remote folder "+toCleanPath,e);
|
||||
throw new RuntimeException("Unable to cleanup remote folder.");
|
||||
}finally {
|
||||
log.debug("Resetting original token {} ",toRestoreToken);
|
||||
TokenSetter.set(toRestoreToken);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static String getThreddsHost(){
|
||||
|
||||
SimpleQuery query =queryFor(GCoreEndpoint.class);
|
||||
query.addCondition("$resource/Profile/ServiceClass/text() eq 'SDI'")
|
||||
.addCondition("$resource/Profile/ServiceName/text() eq 'Thredds'");
|
||||
// .setResult("$resource/Profile/AccessPoint");
|
||||
|
||||
DiscoveryClient<GCoreEndpoint> client = clientFor(GCoreEndpoint.class);
|
||||
|
||||
GCoreEndpoint endpoint= client.submit(query).get(0);
|
||||
|
||||
return endpoint.profile().endpoints().iterator().next().uri().getHost();
|
||||
}
|
||||
|
||||
public static DataTransferClient getDTClient(String threddsHostName) throws UnreachableNodeException, ServiceNotFoundException {
|
||||
log.debug("Getting DT Client for {} ",threddsHostName);
|
||||
return DataTransferClient.getInstanceByEndpoint("http://"+threddsHostName+":80");
|
||||
}
|
||||
|
||||
public static String readThreddsFile(String location) throws RemoteFileNotFoundException {
|
||||
String urlString="http://"+getThreddsHost()+":80/"+Constants.THREDDS_DATA_TRANSFER_BASE_URL+location;
|
||||
log.info("Reading file at {} ",urlString);
|
||||
try{
|
||||
return getWebClient().target(urlString).request().get().readEntity(String.class);
|
||||
}catch(Throwable t) {
|
||||
throw new RemoteFileNotFoundException("Unable to access "+urlString, t);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static void deleteThreddsFile(String location) throws RemoteFileNotFoundException {
|
||||
String urlString="http://"+getThreddsHost()+":80/"+Constants.THREDDS_DATA_TRANSFER_BASE_URL+location;
|
||||
log.info("Reading file at {} ",urlString);
|
||||
try{
|
||||
getWebClient().target(urlString).request().delete();
|
||||
}catch(Throwable t) {
|
||||
throw new RemoteFileNotFoundException("Unable to access "+urlString, t);
|
||||
}
|
||||
}
|
||||
|
||||
public static final ThreddsInfo getThreddsInfo() {
|
||||
String infoPath=getThreddsInfoPath();
|
||||
log.info("Loading thredds info from {} ",infoPath);
|
||||
WebTarget target=getWebClient().target(infoPath);
|
||||
return target.request(MediaType.APPLICATION_JSON).get(ThreddsInfo.class);
|
||||
}
|
||||
|
||||
private static Client getWebClient() {
|
||||
return ClientBuilder.newClient(new ClientConfig().register(AuthorizationFilter.class));
|
||||
}
|
||||
|
||||
private static String getThreddsInfoPath() {
|
||||
return "https://"+getThreddsHost()+"/data-transfer-service/gcube/service/Capabilities/pluginInfo/REGISTER_CATALOG";
|
||||
}
|
||||
|
||||
public static void lockFolder(String folderPath,String processId) throws UnableToLockException {
|
||||
PrintWriter writer=null;
|
||||
File temp=null;
|
||||
try{
|
||||
log.info("Locking remote path {} to processId {} ",folderPath,processId);
|
||||
DataTransferClient cl=getDTClient(getThreddsHost());
|
||||
|
||||
Destination dest=new Destination();
|
||||
dest.setCreateSubfolders(false);
|
||||
dest.setOnExistingFileName(DestinationClashPolicy.FAIL);
|
||||
dest.setOnExistingSubFolder(DestinationClashPolicy.APPEND);
|
||||
dest.setPersistenceId("thredds");
|
||||
dest.setSubFolder(folderPath);
|
||||
dest.setDestinationFileName(Constants.LOCK_FILE);
|
||||
|
||||
temp=File.createTempFile("tmp_lock", ".tmp");
|
||||
writer=new PrintWriter(temp);
|
||||
writer.write(processId);
|
||||
writer.flush();
|
||||
writer.close();
|
||||
|
||||
cl.localFile(temp, dest);
|
||||
}catch(Throwable t) {
|
||||
throw new UnableToLockException("Unable to lock "+folderPath,t);
|
||||
}finally {
|
||||
if(writer!=null) IOUtils.closeQuietly(writer);
|
||||
if(temp!=null)try {
|
||||
Files.deleteIfExists(temp.toPath());
|
||||
}catch(IOException e) {
|
||||
log.warn("Unable to delete temp file {} ",temp.getAbsolutePath(),e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,94 @@
|
||||
package org.gcube.usecases.ws.thredds;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class Constants {
|
||||
|
||||
public static final SimpleDateFormat DATE_FORMAT= new SimpleDateFormat("dd-MM-yy:HH:mm:SS");
|
||||
|
||||
public static final String LOCK_FILE="~WS-LOCK.lock";
|
||||
public static final String GCUBE_TOKEN_HEADER="gcube-token";
|
||||
|
||||
public static final String LAST_UPDATE_TIME="WS-SYNCH.LAST_UPDATE";
|
||||
|
||||
public static final String THREDDS_PERSISTENCE="thredds";
|
||||
public static final String THREDDS_DATA_TRANSFER_BASE_URL="data-transfer-service/gcube/service/REST/"+THREDDS_PERSISTENCE+"/";
|
||||
|
||||
|
||||
public static final String SDI_THREDDS_BASE_URL="sdi-service/gcube/service/Thredds";
|
||||
|
||||
|
||||
public static final String SIS_PLUGIN_ID="SIS/GEOTK";
|
||||
|
||||
public static class WorkspaceProperties{
|
||||
// Folder
|
||||
public static final String SYNCH_FILTER="WS-SYNCH.SYNCHRONIZATION-FILTER";
|
||||
public static final String TARGET_TOKEN="WS-SYNCH.TARGET-TOKEN";
|
||||
public static final String REMOTE_PATH="WS-SYNCH.REMOTE-PATH";
|
||||
public static final String REMOTE_PERSISTENCE="WS-SYNCH.REMOTE-PERSISTENCE";
|
||||
public static final String RELATED_CATALOG="WS-SYNCH.RELATED-CATALOG";
|
||||
public static final String VALIDATE_METADATA="WS-SYNCH.VALIDATE-METADATA";
|
||||
public static final String ROOT_FOLDER_ID="WS-SYNCH.ROOT-FOLDER-ID";
|
||||
|
||||
|
||||
// Common
|
||||
public static final String TBS="WS-SYNCH.TO-BE-SYNCHRONIZED";
|
||||
public static final String SYNCHRONIZATION_STATUS="WS-SYNCH.SYNCH-STATUS";
|
||||
public static final String LAST_UPDATE_TIME="WS-SYNCH.LAST-UPDATE-TIME";
|
||||
public static final String LAST_UPDATE_STATUS="WS-SYNCH.LAST-UPDATE-STATUS";
|
||||
|
||||
// ITEM
|
||||
public static final String METADATA_UUID="WS-SYNCH.METADATA-UUID";
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static class Configuration{
|
||||
public static final String SCANNER_POOL_MAX_SIZE="scanner.pool.maxSize";
|
||||
public static final String SCANNER_POOL_CORE_SIZE="scanner.pool.coreSize";
|
||||
public static final String SCANNER_POOL_IDLE_MS="scanner.pool.idle.ms";
|
||||
|
||||
public static final String TRANSFERS_POOL_MAX_SIZE="transfers.pool.maxSize";
|
||||
public static final String TRANSFERS_POOL_CORE_SIZE="transfers.pool.coreSize";
|
||||
public static final String TRANSFERS_POOL_IDLE_MS="transfers.pool.idle.ms";
|
||||
}
|
||||
|
||||
public static final Map<String,String> cleanedItemPropertiesMap=new HashMap<String,String>();
|
||||
|
||||
public static final Map<String,String> cleanedFolderPropertiesMap=new HashMap<String,String>();
|
||||
|
||||
public static final Map<String,String> defaultConfigurationMap=new HashMap<String,String>();
|
||||
|
||||
static {
|
||||
cleanedItemPropertiesMap.put(Constants.WorkspaceProperties.TBS, null);
|
||||
cleanedItemPropertiesMap.put(Constants.WorkspaceProperties.LAST_UPDATE_TIME, null);
|
||||
cleanedItemPropertiesMap.put(Constants.WorkspaceProperties.LAST_UPDATE_STATUS, null);
|
||||
cleanedItemPropertiesMap.put(Constants.WorkspaceProperties.SYNCHRONIZATION_STATUS, null);
|
||||
cleanedItemPropertiesMap.put(Constants.WorkspaceProperties.METADATA_UUID, null);
|
||||
|
||||
|
||||
cleanedFolderPropertiesMap.put(Constants.WorkspaceProperties.SYNCH_FILTER, null);
|
||||
cleanedFolderPropertiesMap.put(Constants.WorkspaceProperties.REMOTE_PATH, null);
|
||||
cleanedFolderPropertiesMap.put(Constants.WorkspaceProperties.REMOTE_PERSISTENCE, null);
|
||||
cleanedFolderPropertiesMap.put(Constants.WorkspaceProperties.TARGET_TOKEN, null);
|
||||
cleanedFolderPropertiesMap.put(Constants.WorkspaceProperties.TBS, null);
|
||||
cleanedFolderPropertiesMap.put(Constants.WorkspaceProperties.LAST_UPDATE_TIME, null);
|
||||
cleanedFolderPropertiesMap.put(Constants.WorkspaceProperties.LAST_UPDATE_STATUS, null);
|
||||
cleanedFolderPropertiesMap.put(Constants.WorkspaceProperties.SYNCHRONIZATION_STATUS, null);
|
||||
cleanedFolderPropertiesMap.put(Constants.WorkspaceProperties.RELATED_CATALOG, null);
|
||||
cleanedFolderPropertiesMap.put(Constants.WorkspaceProperties.VALIDATE_METADATA, null);
|
||||
cleanedFolderPropertiesMap.put(Constants.WorkspaceProperties.ROOT_FOLDER_ID, null);
|
||||
|
||||
|
||||
defaultConfigurationMap.put(Configuration.SCANNER_POOL_CORE_SIZE, "1");
|
||||
defaultConfigurationMap.put(Configuration.SCANNER_POOL_MAX_SIZE, "10");
|
||||
defaultConfigurationMap.put(Configuration.SCANNER_POOL_IDLE_MS, "30000");
|
||||
|
||||
defaultConfigurationMap.put(Configuration.TRANSFERS_POOL_CORE_SIZE, "1");
|
||||
defaultConfigurationMap.put(Configuration.TRANSFERS_POOL_MAX_SIZE, "10");
|
||||
defaultConfigurationMap.put(Configuration.TRANSFERS_POOL_IDLE_MS, "30000");
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
package org.gcube.usecases.ws.thredds;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.NonNull;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@RequiredArgsConstructor
|
||||
@ToString
|
||||
public class FolderConfiguration {
|
||||
|
||||
public FolderConfiguration(FolderConfiguration other) {
|
||||
this.providedMetadata=other.providedMetadata;
|
||||
this.includeSubfolders=other.includeSubfolders;
|
||||
this.publishingUserToken=other.publishingUserToken;
|
||||
this.folderId=other.folderId;
|
||||
this.catalogName=other.catalogName;
|
||||
this.metadataFolderId=other.metadataFolderId;
|
||||
}
|
||||
|
||||
|
||||
|
||||
private boolean providedMetadata=false;
|
||||
private boolean includeSubfolders=true;
|
||||
|
||||
|
||||
@NonNull
|
||||
private String publishingUserToken;
|
||||
|
||||
@NonNull
|
||||
private String folderId;
|
||||
@NonNull
|
||||
private String catalogName;
|
||||
|
||||
|
||||
private String metadataFolderId=null;
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
package org.gcube.usecases.ws.thredds;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.NonNull;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@ToString
|
||||
@RequiredArgsConstructor
|
||||
public class FolderReport {
|
||||
|
||||
@NonNull
|
||||
private FolderConfiguration config;
|
||||
private Set<String> transferredFiles=new HashSet<>();
|
||||
|
||||
/* map file->uuid*/
|
||||
private Map<String,String> generatedMetadata=new HashMap<>();
|
||||
private Set<String> publishedMetadata=new HashSet<>();
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,44 @@
|
||||
package org.gcube.usecases.ws.thredds;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
import lombok.Synchronized;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@Slf4j
|
||||
public class LocalConfiguration {
|
||||
|
||||
private static LocalConfiguration instance=null;
|
||||
|
||||
@Synchronized
|
||||
private static final LocalConfiguration get() {
|
||||
if(instance==null)
|
||||
instance=new LocalConfiguration();
|
||||
return instance;
|
||||
}
|
||||
|
||||
public static String getProperty(String property) {
|
||||
try{
|
||||
return (String) get().props.getOrDefault(property, Constants.defaultConfigurationMap.get(property));
|
||||
}catch(Throwable t) {
|
||||
log.warn("Unable to get configuration property "+property,t);
|
||||
return Constants.defaultConfigurationMap.get(property);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//***************** INSTANCE
|
||||
|
||||
Properties props;
|
||||
|
||||
public LocalConfiguration() {
|
||||
props=new Properties();
|
||||
try{
|
||||
props.load(this.getClass().getResourceAsStream("configuration.properties"));
|
||||
}catch(Exception e) {
|
||||
log.warn("********************** UNABLE TO LOAD PROPERTIES **********************",e);
|
||||
log.debug("Reverting to defaults : "+Constants.defaultConfigurationMap);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,57 @@
|
||||
package org.gcube.usecases.ws.thredds;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Slf4j
|
||||
public class NetUtils {
|
||||
|
||||
public static final File toFile(InputStream is) {
|
||||
FileOutputStream outputStream =null;
|
||||
try {
|
||||
File toReturn=File.createTempFile("tempFile", ".tmp");
|
||||
outputStream=new FileOutputStream(toReturn);
|
||||
|
||||
int read = 0;
|
||||
byte[] bytes = new byte[1024];
|
||||
|
||||
while ((read = is.read(bytes)) != -1) {
|
||||
outputStream.write(bytes, 0, read);
|
||||
}
|
||||
return toReturn;
|
||||
}catch(Throwable t) {
|
||||
throw new RuntimeException(t);
|
||||
}finally {
|
||||
if(outputStream!=null) {
|
||||
IOUtils.closeQuietly(outputStream);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static String resolveRedirects(String url) throws IOException{
|
||||
log.debug("Resolving redirect for url {} ",url);
|
||||
URL urlObj=new URL(url);
|
||||
HttpURLConnection connection = (HttpURLConnection) urlObj.openConnection();
|
||||
int status=connection.getResponseCode();
|
||||
if(status>=300&&status<400){
|
||||
String newUrl=connection.getHeaderField("Location");
|
||||
log.debug("Following redirect from {} to {} ",url,newUrl);
|
||||
return resolveRedirects(newUrl);
|
||||
}else return url;
|
||||
}
|
||||
|
||||
|
||||
public static File download(String url) throws MalformedURLException, IOException {
|
||||
return toFile(new URL(resolveRedirects(url)).openStream());
|
||||
}
|
||||
}
|
@ -0,0 +1,283 @@
|
||||
package org.gcube.usecases.ws.thredds;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.gcube.common.homelibrary.home.HomeLibrary;
|
||||
import org.gcube.common.homelibrary.home.exceptions.HomeNotFoundException;
|
||||
import org.gcube.common.homelibrary.home.exceptions.InternalErrorException;
|
||||
import org.gcube.common.homelibrary.home.exceptions.UserNotFoundException;
|
||||
import org.gcube.common.homelibrary.home.workspace.Workspace;
|
||||
import org.gcube.common.homelibrary.home.workspace.WorkspaceFolder;
|
||||
import org.gcube.common.homelibrary.home.workspace.WorkspaceItem;
|
||||
import org.gcube.common.homelibrary.home.workspace.accounting.AccountingEntry;
|
||||
import org.gcube.common.homelibrary.home.workspace.exceptions.ItemNotFoundException;
|
||||
import org.gcube.common.homelibrary.home.workspace.exceptions.WorkspaceException;
|
||||
import org.gcube.common.homelibrary.home.workspace.exceptions.WrongItemTypeException;
|
||||
import org.gcube.common.homelibrary.home.workspace.folder.items.ExternalFile;
|
||||
import org.gcube.usecases.ws.thredds.engine.PublishRequest;
|
||||
import org.gcube.usecases.ws.thredds.engine.PublishRequest.Mode;
|
||||
import org.gcube.usecases.ws.thredds.engine.PublishRequest.PublishItem;
|
||||
import org.gcube.usecases.ws.thredds.engine.TransferRequestServer;
|
||||
import org.gcube.usecases.ws.thredds.engine.TransferRequestServer.Report;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Slf4j
|
||||
public class PublishFolders {
|
||||
|
||||
private static String WS_USER="fabio.sinibaldi";
|
||||
|
||||
|
||||
public static void main(String[] args) {
|
||||
TokenSetter.set("/d4science.research-infrastructures.eu");
|
||||
HashSet<FolderConfiguration> configs=new HashSet<>();
|
||||
|
||||
|
||||
// String folderId="be451663-4d4f-4e23-a2c8-060cf15d83a7"; // NETCDF DATASETS
|
||||
// String metadataFolderID="2de04273-ca79-4478-a593-354c5a12f942"; //metadata files
|
||||
String folderId="a8cd78d3-69e8-4d02-ac90-681b2d16d84d"; // GP DDOS TEST
|
||||
|
||||
// String folderId="a711a8d7-5e93-498f-a29c-b888d7c2e48f"; TICKET
|
||||
|
||||
String publishingUserToken="5741e3e4-dbde-46fa-828d-88da609e0517-98187548"; //fabio @NextNext
|
||||
|
||||
|
||||
FolderConfiguration folderConfig=new FolderConfiguration(publishingUserToken,folderId,"GP_CASE");
|
||||
// folderConfig.setProvidedMetadata(true);
|
||||
// folderConfig.setMetadataFolderId(metadataFolderID);
|
||||
|
||||
|
||||
|
||||
|
||||
configs.add(folderConfig);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
TransferRequestServer server=new TransferRequestServer();
|
||||
for(FolderConfiguration entry:configs){
|
||||
try{
|
||||
Workspace ws = HomeLibrary.getHomeManagerFactory().getHomeManager().getHome(WS_USER).getWorkspace();
|
||||
// FolderReport report=new FolderReport(entry);
|
||||
log.info("Managing {} ",entry);
|
||||
WorkspaceFolder folder = (WorkspaceFolder) ws.getItem(entry.getFolderId());
|
||||
handleFolder(ws,entry,server,folder);
|
||||
|
||||
|
||||
|
||||
}catch(WorkspaceException e){
|
||||
System.err.println("WORKSPACE EXC ");
|
||||
e.printStackTrace(System.err);
|
||||
}catch(HomeNotFoundException e){
|
||||
System.err.println("WORKSPACE EXC ");
|
||||
e.printStackTrace(System.err);
|
||||
}catch(InternalErrorException e){
|
||||
System.err.println("WORKSPACE EXC ");
|
||||
e.printStackTrace(System.err);
|
||||
}catch(UserNotFoundException e){
|
||||
System.err.println("WORKSPACE EXC ");
|
||||
e.printStackTrace(System.err);
|
||||
}catch(Exception e){
|
||||
System.err.println("UNEXPECTED EXC");
|
||||
e.printStackTrace(System.err);
|
||||
}
|
||||
}
|
||||
System.out.println("Waiting for service.. ");
|
||||
server.waitCompletion();
|
||||
|
||||
Report report=server.getReport();
|
||||
|
||||
File reportFile =report.toFile(folderConfig);
|
||||
System.out.println("Report at "+reportFile.getAbsolutePath());
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* For *.nc | *.ncml
|
||||
* if relatedMetadataFolder contains <filename>.xml use meta
|
||||
* else ask DT to generate it
|
||||
*
|
||||
*
|
||||
* @param wsFolder
|
||||
* @param config
|
||||
* @param server
|
||||
* @return
|
||||
* @throws WorkspaceException
|
||||
* @throws InternalErrorException
|
||||
* @throws ItemNotFoundException
|
||||
* @throws HomeNotFoundException
|
||||
* @throws UserNotFoundException
|
||||
*/
|
||||
|
||||
public static final void handleFolder(Workspace ws, FolderConfiguration config,TransferRequestServer server, WorkspaceFolder folder) throws InternalErrorException, ItemNotFoundException{
|
||||
|
||||
log.info("Handling folder {} ",folder.getPath());
|
||||
|
||||
cleanUpForFileRemoval(ws, folder, config.getPublishingUserToken(),config.getCatalogName());
|
||||
|
||||
log.info("Folder {} cleaned up. Going to publish phase..",folder.getPath());
|
||||
publishFolder(ws,config,server,folder);
|
||||
}
|
||||
|
||||
|
||||
public static final void publishFolder(Workspace ws, FolderConfiguration config,TransferRequestServer server, WorkspaceFolder folder) throws InternalErrorException, ItemNotFoundException{
|
||||
|
||||
|
||||
|
||||
|
||||
//Access folder
|
||||
List<WorkspaceItem> folderItems=folder.getChildren();
|
||||
|
||||
if(config.isIncludeSubfolders()) {
|
||||
log.info("Going through subfolders first.....");
|
||||
for(WorkspaceItem item:folderItems) {
|
||||
try {
|
||||
if(item.isFolder()) {
|
||||
FolderConfiguration subConfig=new FolderConfiguration(config);
|
||||
subConfig.setCatalogName(config.getCatalogName()+"/"+item.getName());
|
||||
publishFolder(ws,subConfig,server,(WorkspaceFolder) item);
|
||||
log.debug("Subfolder {} successfully analyzed ",item.getPath());
|
||||
}
|
||||
}catch(Exception e) {
|
||||
try{
|
||||
log.warn("Unabel to check item {} ",item.getPath(),e);
|
||||
}catch(InternalErrorException e1) {
|
||||
log.warn("Unabel to check item and to get Path {} ",item,e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
log.debug("Checking for ncml files .... ");
|
||||
for(WorkspaceItem item : folderItems) {
|
||||
try {
|
||||
if(!item.isFolder()) {
|
||||
String prefix=item.getName().substring(item.getName().lastIndexOf("."), item.getName().length());
|
||||
if(prefix.equals(".ncml")) {
|
||||
PublishRequest req=new PublishRequest(new PublishItem(item),Mode.NCML, config.getCatalogName(), config.getPublishingUserToken());
|
||||
if(config.isProvidedMetadata()) {
|
||||
String toLookForName=item.getName().substring(0, item.getName().lastIndexOf(prefix))+".xml";
|
||||
File meta=getMetadataForDataset(ws, toLookForName, config.getMetadataFolderId());
|
||||
if (meta!=null) req.setMetadata(meta);
|
||||
}
|
||||
// TODO NB Check for queue
|
||||
server.put(req);
|
||||
}
|
||||
}
|
||||
}catch(Exception e) {
|
||||
try{
|
||||
log.warn("Unabel to check item {} ",item.getPath(),e);
|
||||
}catch(InternalErrorException e1) {
|
||||
log.warn("Unabel to check item and to get Path {} ",item,e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
log.debug("Checking nc files.. ");
|
||||
|
||||
for(WorkspaceItem item:folder.getChildren()){
|
||||
try {
|
||||
if(!item.isFolder()) {
|
||||
String prefix=item.getName().substring(item.getName().lastIndexOf("."), item.getName().length());
|
||||
if(prefix.equals(".nc")){
|
||||
// NC
|
||||
PublishRequest req=new PublishRequest(new PublishItem(item),Mode.NC, config.getCatalogName(), config.getPublishingUserToken());
|
||||
if(config.isProvidedMetadata()) {
|
||||
String toLookForName=item.getName().substring(0, item.getName().lastIndexOf(prefix))+".xml";
|
||||
File meta=getMetadataForDataset(ws, toLookForName, config.getMetadataFolderId());
|
||||
if (meta!=null) req.setMetadata(meta);
|
||||
}
|
||||
server.put(req);
|
||||
}
|
||||
}
|
||||
}catch(Exception e) {
|
||||
try{
|
||||
log.warn("Unabel to check item {} ",item.getPath(),e);
|
||||
}catch(InternalErrorException e1) {
|
||||
log.warn("Unabel to check item and to get Path {} ",item,e);
|
||||
}
|
||||
}
|
||||
}
|
||||
folder.getProperties().addProperties(Collections.singletonMap(Constants.LAST_UPDATE_TIME, System.currentTimeMillis()+""));
|
||||
log.debug("Creating requests... ");
|
||||
}
|
||||
|
||||
private static final File getMetadataForDataset(Workspace userWorkspace, String toLookForName, String metadataFolderId) throws WrongItemTypeException, InternalErrorException {
|
||||
try{
|
||||
WorkspaceItem found=userWorkspace.find(toLookForName,metadataFolderId);
|
||||
if(found==null) throw new ItemNotFoundException("Found item was null");
|
||||
return NetUtils.toFile(((ExternalFile)found).getData());
|
||||
}catch(ItemNotFoundException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// Remotely deletes folders which has history operations : RENAMING, REMOVAL
|
||||
private static final void cleanUpForFileRemoval(Workspace ws, WorkspaceFolder folder,String targetToken, String remoteFolderPath) throws InternalErrorException {
|
||||
List<AccountingEntry> history=folder.getAccounting();
|
||||
long lastUpdateTimeMillis=getLastUpdateTime(folder);
|
||||
Date lastUpdate=new Date(lastUpdateTimeMillis);
|
||||
log.info("Checking history for {} (last update time {}) ",folder.getPath(),Commons.DATE_FORMAT.format(lastUpdate));
|
||||
|
||||
|
||||
//look into history
|
||||
boolean toDeleteCurrentFolder=false;
|
||||
for(AccountingEntry entry: history) {
|
||||
Date eventTime=entry.getDate().getTime();
|
||||
|
||||
switch(entry.getEntryType()) {
|
||||
case REMOVAL:
|
||||
|
||||
case RENAMING:{
|
||||
log.debug("Found Accounting Entry [type : {}, date {}] ",entry.getEntryType(),Commons.DATE_FORMAT.format(eventTime));
|
||||
if(eventTime.after(lastUpdate)) {
|
||||
log.info("Found Accounting Entry [type : {}, date {}]. Removing remote folder. ",entry.getEntryType(),Commons.DATE_FORMAT.format(eventTime));
|
||||
toDeleteCurrentFolder=true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(toDeleteCurrentFolder) break;
|
||||
}
|
||||
|
||||
|
||||
//Delete Folder or scan children
|
||||
if(toDeleteCurrentFolder) {
|
||||
log.info("Deleting current folder {} from remote location {} ",folder.getPath(),remoteFolderPath);
|
||||
try{
|
||||
Commons.cleanupFolder(remoteFolderPath,targetToken);
|
||||
}catch(Throwable t) {
|
||||
log.warn("Unable To cleanup folder {} . Remote Folder might not exists. If this is first publishing ignor this.",remoteFolderPath,t);
|
||||
if(lastUpdateTimeMillis!=0) // do no rethrow in case of first publish
|
||||
throw t;
|
||||
|
||||
}
|
||||
}else {
|
||||
log.info("Folder is not to be cleaned up. Checking children..");
|
||||
for(WorkspaceItem item:folder.getChildren())
|
||||
if(item.isFolder())cleanUpForFileRemoval(ws, (WorkspaceFolder) item,targetToken, remoteFolderPath+"/"+item.getName());
|
||||
}
|
||||
}
|
||||
|
||||
private static long getLastUpdateTime(WorkspaceItem item) throws InternalErrorException {
|
||||
try{
|
||||
return Long.parseLong(item.getProperties().getPropertyValue(Constants.LAST_UPDATE_TIME));
|
||||
}catch(Throwable e) {
|
||||
log.debug("Unable to get last update time for {}. Considering 0..",item.getPath());
|
||||
return 0l;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,57 @@
|
||||
package org.gcube.usecases.ws.thredds;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Set;
|
||||
|
||||
import org.gcube.usecases.ws.thredds.engine.impl.ProcessDescriptor;
|
||||
import org.gcube.usecases.ws.thredds.engine.impl.ProcessStatus;
|
||||
import org.gcube.usecases.ws.thredds.engine.impl.SynchEngineImpl;
|
||||
import org.gcube.usecases.ws.thredds.faults.InternalException;
|
||||
import org.gcube.usecases.ws.thredds.faults.ProcessNotFoundException;
|
||||
import org.gcube.usecases.ws.thredds.faults.WorkspaceInteractionException;
|
||||
import org.gcube.usecases.ws.thredds.model.SyncFolderDescriptor;
|
||||
import org.gcube.usecases.ws.thredds.model.SyncOperationCallBack;
|
||||
import org.gcube.usecases.ws.thredds.model.SynchFolderConfiguration;
|
||||
import org.gcube.usecases.ws.thredds.model.SynchronizedElementInfo;
|
||||
import org.gcube.usecases.ws.thredds.model.gui.CatalogBean;
|
||||
|
||||
public interface SyncEngine {
|
||||
|
||||
public static SyncEngine get() {
|
||||
return SynchEngineImpl.get();
|
||||
}
|
||||
|
||||
|
||||
public SyncFolderDescriptor check(String folderId, boolean recursively) throws WorkspaceInteractionException, InternalException;
|
||||
public void registerCallBack(String folderId,SyncOperationCallBack callback) throws ProcessNotFoundException;
|
||||
public ProcessDescriptor doSync(String folderId) throws WorkspaceInteractionException, InternalException;
|
||||
public void stopSynch(String folderId) throws ProcessNotFoundException;
|
||||
|
||||
public void setSynchronizedFolder(SynchFolderConfiguration config,String folderId) throws WorkspaceInteractionException, InternalException;
|
||||
public void unsetSynchronizedFolder(String folderId,boolean deleteRemoteContent) throws WorkspaceInteractionException, InternalException;
|
||||
|
||||
public SynchronizedElementInfo getInfo(String elementId);
|
||||
|
||||
public void updateCatalogFile(String folderId, File toUpdate) throws InternalException;
|
||||
|
||||
public void forceUnlock(String folderId)throws InternalException, WorkspaceInteractionException;
|
||||
|
||||
|
||||
public void shutDown();
|
||||
|
||||
|
||||
public ProcessDescriptor getProcessDescriptorByFolderId(String folderId)throws ProcessNotFoundException;
|
||||
public ProcessStatus getProcessStatusByFolderId(String folderId)throws ProcessNotFoundException;
|
||||
|
||||
|
||||
|
||||
public void setRequestLogger(String path);
|
||||
public boolean isRequestLoggerEnabled();
|
||||
public String getRequestLoggerPath();
|
||||
|
||||
|
||||
public Set<CatalogBean> getAvailableCatalogsByToken(String token) throws InternalException;
|
||||
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,55 @@
|
||||
package org.gcube.usecases.ws.thredds;
|
||||
|
||||
import static org.gcube.common.authorization.client.Constants.authorizationService;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
import org.gcube.common.authorization.library.AuthorizationEntry;
|
||||
import org.gcube.common.authorization.library.provider.SecurityTokenProvider;
|
||||
import org.gcube.common.scope.api.ScopeProvider;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Slf4j
|
||||
public class TokenSetter {
|
||||
|
||||
private static Properties props=null;
|
||||
|
||||
static{
|
||||
|
||||
}
|
||||
|
||||
|
||||
public static synchronized void set(String scope){
|
||||
try{
|
||||
if(props==null) {
|
||||
props=new Properties();
|
||||
try {
|
||||
props.load(TokenSetter.class.getResourceAsStream("/tokens.properties"));
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("YOU NEED TO SET TOKEN FILE IN CONFIGURATION");
|
||||
}
|
||||
}
|
||||
if(!props.containsKey(scope)) throw new Exception("No token found for scope : "+scope);
|
||||
SecurityTokenProvider.instance.set(props.getProperty(scope));
|
||||
}catch(Throwable e){
|
||||
log.trace("Unable to set token for scope "+scope,e);
|
||||
}
|
||||
ScopeProvider.instance.set(scope);
|
||||
}
|
||||
|
||||
|
||||
public static void setToken(String token){
|
||||
try{
|
||||
AuthorizationEntry entry = authorizationService().get(token);
|
||||
ScopeProvider.instance.set(entry.getContext());
|
||||
SecurityTokenProvider.instance.set(token);
|
||||
}catch(Throwable t) {
|
||||
throw new RuntimeException("Unable to set token "+token,t);
|
||||
}
|
||||
}
|
||||
|
||||
public static String getCurrentToken() {
|
||||
return SecurityTokenProvider.instance.get();
|
||||
}
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
package org.gcube.usecases.ws.thredds.engine;
|
||||
|
||||
import org.gcube.data.transfer.library.TransferResult;
|
||||
import org.gcube.spatial.data.sdi.model.metadata.MetadataReport;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
public class PublishReport {
|
||||
|
||||
boolean isError=false;
|
||||
|
||||
|
||||
private String sourceId;
|
||||
private String sourceName;
|
||||
|
||||
private TransferResult transferResult;
|
||||
private MetadataReport metadataReport;
|
||||
|
||||
}
|
@ -0,0 +1,64 @@
|
||||
package org.gcube.usecases.ws.thredds.engine;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.HashSet;
|
||||
|
||||
import org.gcube.common.homelibrary.home.exceptions.InternalErrorException;
|
||||
import org.gcube.common.homelibrary.home.workspace.WorkspaceItem;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.Getter;
|
||||
import lombok.NonNull;
|
||||
import lombok.ToString;
|
||||
|
||||
@Data
|
||||
public class PublishRequest {
|
||||
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
@ToString
|
||||
public static class PublishItem{
|
||||
String url;
|
||||
String name;
|
||||
String id;
|
||||
|
||||
public PublishItem(WorkspaceItem item) throws InternalErrorException {
|
||||
url=item.getPublicLink(false);
|
||||
name=item.getName();
|
||||
id=item.getId();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
public static enum Mode{
|
||||
NCML,NC
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private PublishItem source;
|
||||
@NonNull
|
||||
private Mode mode;
|
||||
@NonNull
|
||||
private String catalog;
|
||||
@NonNull
|
||||
private String publishToken;
|
||||
|
||||
|
||||
private Integer queueCount=0;
|
||||
private String queueId;
|
||||
private File metadata=null;
|
||||
|
||||
|
||||
private HashSet<String> toGatherReportsId=null;
|
||||
|
||||
public boolean isQueue() {
|
||||
return queueCount>0;
|
||||
}
|
||||
|
||||
|
||||
public boolean isGenerateMeta() {
|
||||
return metadata==null;
|
||||
}
|
||||
}
|
@ -0,0 +1,217 @@
|
||||
package org.gcube.usecases.ws.thredds.engine;
|
||||
|
||||
import static org.gcube.resources.discovery.icclient.ICFactory.clientFor;
|
||||
import static org.gcube.resources.discovery.icclient.ICFactory.queryFor;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.nio.file.Files;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.Semaphore;
|
||||
|
||||
import org.gcube.common.authorization.library.provider.SecurityTokenProvider;
|
||||
import org.gcube.common.resources.gcore.GCoreEndpoint;
|
||||
import org.gcube.data.transfer.library.DataTransferClient;
|
||||
import org.gcube.data.transfer.library.TransferResult;
|
||||
import org.gcube.data.transfer.library.faults.DestinationNotSetException;
|
||||
import org.gcube.data.transfer.library.faults.FailedTransferException;
|
||||
import org.gcube.data.transfer.library.faults.InitializationException;
|
||||
import org.gcube.data.transfer.library.faults.InvalidDestinationException;
|
||||
import org.gcube.data.transfer.library.faults.InvalidSourceException;
|
||||
import org.gcube.data.transfer.library.faults.ServiceNotFoundException;
|
||||
import org.gcube.data.transfer.library.faults.SourceNotSetException;
|
||||
import org.gcube.data.transfer.library.faults.UnreachableNodeException;
|
||||
import org.gcube.data.transfer.model.Destination;
|
||||
import org.gcube.data.transfer.model.DestinationClashPolicy;
|
||||
import org.gcube.data.transfer.model.PluginInvocation;
|
||||
import org.gcube.resources.discovery.client.api.DiscoveryClient;
|
||||
import org.gcube.resources.discovery.client.queries.api.SimpleQuery;
|
||||
import org.gcube.spatial.data.sdi.interfaces.Metadata;
|
||||
import org.gcube.spatial.data.sdi.model.metadata.MetadataPublishOptions;
|
||||
import org.gcube.spatial.data.sdi.model.metadata.MetadataReport;
|
||||
import org.gcube.spatial.data.sdi.model.metadata.TemplateInvocationBuilder;
|
||||
import org.gcube.spatial.data.sdi.plugins.SDIAbstractPlugin;
|
||||
import org.gcube.spatial.data.sdi.utils.ScopeUtils;
|
||||
import org.gcube.usecases.ws.thredds.Commons;
|
||||
import org.gcube.usecases.ws.thredds.NetUtils;
|
||||
import org.gcube.usecases.ws.thredds.TokenSetter;
|
||||
import org.gcube.usecases.ws.thredds.engine.PublishRequest.Mode;
|
||||
|
||||
import lombok.NonNull;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class PublishThread implements Runnable {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@NonNull
|
||||
private PublishRequest request;
|
||||
@NonNull
|
||||
private ConcurrentHashMap<String,PublishReport> reports;
|
||||
|
||||
|
||||
private PublishReport publishReport;
|
||||
// private Map<String,Report> reports;
|
||||
//
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
log.info("Request is {}",request);
|
||||
log.debug("Switching from {} to {}",SecurityTokenProvider.instance.get(),request.getPublishToken());
|
||||
TokenSetter.setToken(request.getPublishToken());
|
||||
log.debug("Current scope is :{}, token is {} ",ScopeUtils.getCurrentScope(),SecurityTokenProvider.instance.get());
|
||||
|
||||
Destination dest=new Destination();
|
||||
dest.setPersistenceId("thredds");
|
||||
dest.setSubFolder("public/netcdf/"+request.getCatalog());
|
||||
dest.setOnExistingFileName(DestinationClashPolicy.REWRITE);
|
||||
dest.setCreateSubfolders(true);
|
||||
dest.setOnExistingSubFolder(DestinationClashPolicy.APPEND);
|
||||
String threddsHostName;
|
||||
|
||||
|
||||
try {
|
||||
threddsHostName = Commons.getThreddsHost();
|
||||
|
||||
DataTransferClient client=Commons.getDTClient(threddsHostName);
|
||||
|
||||
|
||||
File toPublishSource=null;
|
||||
|
||||
if(request.getMode().equals(Mode.NCML)) {
|
||||
if(request.isQueue()){
|
||||
log.debug("Waiting for queue {}, expected Count {} ",request.getQueueId(),request.getQueueCount());
|
||||
waitFor(request.getQueueId(), request.getQueueCount());
|
||||
|
||||
log.debug("Loading netcdfFile ..");
|
||||
File ncmlFile=NetUtils.download(request.getSource().getUrl());
|
||||
String toUpdateSource=new String(Files.readAllBytes(ncmlFile.toPath()));
|
||||
|
||||
for(String reportId:request.getToGatherReportsId()) {
|
||||
PublishReport report=getReport(reportId);
|
||||
//file://home/gcube/julien.barde/Workspace/DataMiner/Output_Data_Sets/Ichthyop2013.nc
|
||||
|
||||
String toSetUrl="file:/"+report.getTransferResult().getRemotePath();
|
||||
toUpdateSource=toUpdateSource.replaceAll(reportId, toSetUrl);
|
||||
}
|
||||
|
||||
toPublishSource=File.createTempFile("nc_", ".ncml");
|
||||
PrintWriter out = new PrintWriter(toPublishSource);
|
||||
out.write(toUpdateSource);
|
||||
out.flush();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
TransferResult result;
|
||||
|
||||
|
||||
// TODO NB Test run without metadata publication
|
||||
// result=client.httpSource(request.getSource().getUrl(), dest);
|
||||
// publishReport=new PublishReport(false,request.getSource().getId(),result,null);
|
||||
|
||||
|
||||
if(!request.isGenerateMeta()) {
|
||||
log.debug("Transfering before publishing meta..");
|
||||
|
||||
result = toPublishSource==null?client.httpSource(request.getSource().getUrl(), dest):
|
||||
client.localFile(toPublishSource, dest);
|
||||
|
||||
//NB DECOMMENT THIS!!!!!!
|
||||
// Metadata meta=SDIAbstractPlugin.metadata().build();
|
||||
//
|
||||
// log.debug("Publishing metadata.. ");
|
||||
//
|
||||
// MetadataPublishOptions opts=new MetadataPublishOptions(new TemplateInvocationBuilder().threddsOnlineResources(threddsHostName, request.getSource().getName(), request.getCatalog()).get());
|
||||
// opts.setGeonetworkCategory("Datasets");
|
||||
// MetadataReport report=meta.pushMetadata(request.getMetadata(), opts);
|
||||
|
||||
// publishReport=new PublishReport(false,request.getSource().getId(),request.getSource().getName(),result,report);
|
||||
publishReport=new PublishReport(false,request.getSource().getId(),request.getSource().getName(),result,new MetadataReport());
|
||||
|
||||
|
||||
}else {
|
||||
log.debug("Metadata not provided.. ");
|
||||
if(request.isQueue()&&request.getMode().equals(Mode.NC)) {
|
||||
log.debug("Dataset file is linked in ncml, skipping metadata generation");
|
||||
result=client.httpSource(request.getSource().getUrl(), dest);
|
||||
}else
|
||||
result=client.httpSource(request.getSource().getUrl(), dest,new PluginInvocation("SIS/GEOTK"));
|
||||
|
||||
|
||||
publishReport=new PublishReport(false,request.getSource().getId(),request.getSource().getName(),result,null);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
} catch (UnreachableNodeException | ServiceNotFoundException e) {
|
||||
log.error("Unable to find Thredds. Publish scope is {} ",ScopeUtils.getCurrentScope(),e);
|
||||
} catch (InvalidSourceException | SourceNotSetException | FailedTransferException | InitializationException
|
||||
| InvalidDestinationException | DestinationNotSetException e) {
|
||||
log.error("Unable to transfer file, ",e);
|
||||
} catch (IOException e) {
|
||||
log.error("Unable to read/ write file. ",e);
|
||||
}
|
||||
|
||||
onCompletion();
|
||||
}
|
||||
|
||||
|
||||
private void onCompletion() {
|
||||
if(publishReport==null) publishReport=new PublishReport(true, request.getSource().getId(),request.getSource().getName(), null, null);
|
||||
publishReport(publishReport);
|
||||
|
||||
if(request.getMode().equals(Mode.NC)&&(request.isQueue())) {
|
||||
alert(request.getQueueId(),request.getQueueCount());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
private PublishReport getReport(String reportId) {
|
||||
return reports.get(reportId);
|
||||
}
|
||||
|
||||
|
||||
private void publishReport(PublishReport report) {
|
||||
reports.put(report.getSourceId(), report);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// static
|
||||
|
||||
|
||||
private static ConcurrentHashMap<String,Semaphore> semaphores=new ConcurrentHashMap<>();
|
||||
|
||||
|
||||
|
||||
private static void waitFor(String queueId,Integer expected) {
|
||||
try {
|
||||
log.debug("Waiting for queue {}. Expected Count is {} ",queueId,expected);
|
||||
semaphores.getOrDefault(queueId, new Semaphore(expected*-1)).acquire();
|
||||
} catch (InterruptedException e) {
|
||||
log.debug("Queue {} is completed.");
|
||||
}
|
||||
}
|
||||
|
||||
private static void alert(String queueId, Integer expected) {
|
||||
log.debug("Alerting queue {}. Expected count is {} ",queueId,expected);
|
||||
Semaphore sem=semaphores.getOrDefault(queueId, new Semaphore(expected*-1));
|
||||
sem.release();
|
||||
log.debug("Queue {} alerted. Remaining : {} out of {} ",queueId,sem.availablePermits(),expected);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,102 @@
|
||||
package org.gcube.usecases.ws.thredds.engine;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.LinkedBlockingDeque;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.gcube.usecases.ws.thredds.FolderConfiguration;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.Synchronized;
|
||||
|
||||
public class TransferRequestServer {
|
||||
|
||||
@Data
|
||||
public static class Report{
|
||||
private AtomicLong requestCount=new AtomicLong(0l);
|
||||
private AtomicLong requestServed=new AtomicLong(0l);
|
||||
private ConcurrentHashMap<String,PublishReport> reports=new ConcurrentHashMap<>();
|
||||
|
||||
|
||||
public File toFile(FolderConfiguration configuration) {
|
||||
return toFile(configuration,this);
|
||||
}
|
||||
|
||||
|
||||
private static final File toFile(FolderConfiguration config,Report report) {
|
||||
PrintWriter writer =null;
|
||||
try {
|
||||
File toReturn=File.createTempFile("tempFile", ".tmp");
|
||||
writer=new PrintWriter(toReturn);
|
||||
|
||||
writer.println("REPORT FOR WS-SYNCH");
|
||||
writer.println("Configuratiion was : "+config);
|
||||
writer.println("Submitted runs : "+report.getRequestCount());
|
||||
writer.println("Item reports : ");
|
||||
for(Entry<String,PublishReport> entry: report.getReports().entrySet()) {
|
||||
PublishReport rep=entry.getValue();
|
||||
writer.println("*********************************************************");
|
||||
if(rep.isError()) writer.println("OPERATION IS FAILED");
|
||||
writer.println("ITEM ID : "+rep.getSourceId());
|
||||
writer.println("ITEM NAME : "+rep.getSourceName());
|
||||
if(rep.getTransferResult()!=null)writer.println("Transfer report : "+rep.getTransferResult());
|
||||
if(rep.getMetadataReport()!=null)writer.println("Metadata report : "+rep.getMetadataReport());
|
||||
}
|
||||
return toReturn;
|
||||
}catch(Throwable t) {
|
||||
throw new RuntimeException(t);
|
||||
}finally {
|
||||
if(writer!=null) {
|
||||
IOUtils.closeQuietly(writer);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Report report=new Report();
|
||||
private ExecutorService service=null;
|
||||
|
||||
public TransferRequestServer() {
|
||||
BlockingQueue<Runnable> linkedBlockingDeque = new LinkedBlockingDeque<Runnable>(
|
||||
100);
|
||||
service= new ThreadPoolExecutor(1, 10, 30,
|
||||
TimeUnit.SECONDS, linkedBlockingDeque,
|
||||
new ThreadPoolExecutor.CallerRunsPolicy());
|
||||
}
|
||||
|
||||
|
||||
public void put(PublishRequest request){
|
||||
System.out.println("Submitting transfer "+getReport().requestCount.incrementAndGet());
|
||||
service.execute(new PublishThread(request, getReport().getReports()));
|
||||
|
||||
// service.execute(new RequestThread(baseUrl,filename,this,publishScope,toPublishMeta));
|
||||
}
|
||||
@Synchronized
|
||||
public Report getReport(){
|
||||
return report;
|
||||
}
|
||||
|
||||
|
||||
public void waitCompletion() {
|
||||
boolean running=true;
|
||||
service.shutdown();
|
||||
while(running){
|
||||
System.out.println("******************* WAITING FOR TERMINATION ***************** ");
|
||||
try{
|
||||
running=!service.awaitTermination(Long.MAX_VALUE, TimeUnit.MINUTES);
|
||||
}catch(InterruptedException e){
|
||||
running=!service.isTerminated();
|
||||
}
|
||||
}
|
||||
System.out.println("Service is completed : "+service.isTerminated());
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,312 @@
|
||||
package org.gcube.usecases.ws.thredds.engine.impl;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Queue;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
|
||||
import org.gcube.common.homelibrary.home.exceptions.InternalErrorException;
|
||||
import org.gcube.common.homelibrary.home.workspace.WorkspaceFolder;
|
||||
import org.gcube.common.homelibrary.home.workspace.WorkspaceItem;
|
||||
import org.gcube.data.transfer.model.RemoteFileDescriptor;
|
||||
import org.gcube.usecases.ws.thredds.Constants;
|
||||
import org.gcube.usecases.ws.thredds.engine.impl.ProcessStatus.Status;
|
||||
import org.gcube.usecases.ws.thredds.engine.impl.threads.SynchronizationRequest;
|
||||
import org.gcube.usecases.ws.thredds.engine.impl.threads.SynchronizationThread;
|
||||
import org.gcube.usecases.ws.thredds.engine.impl.threads.TransferFromThreddsRequest;
|
||||
import org.gcube.usecases.ws.thredds.engine.impl.threads.TransferToThreddsRequest;
|
||||
import org.gcube.usecases.ws.thredds.faults.InternalException;
|
||||
import org.gcube.usecases.ws.thredds.faults.RemoteFileNotFoundException;
|
||||
import org.gcube.usecases.ws.thredds.faults.WorkspaceInteractionException;
|
||||
import org.gcube.usecases.ws.thredds.faults.WorkspaceNotSynchedException;
|
||||
import org.gcube.usecases.ws.thredds.model.CompletionCallback;
|
||||
import org.gcube.usecases.ws.thredds.model.StepReport;
|
||||
import org.gcube.usecases.ws.thredds.model.SyncOperationCallBack;
|
||||
import org.gcube.usecases.ws.thredds.model.SynchFolderConfiguration;
|
||||
import org.gcube.usecases.ws.thredds.model.SynchronizedElementInfo.SynchronizationStatus;
|
||||
|
||||
import lombok.Synchronized;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Slf4j
|
||||
public class Process {
|
||||
|
||||
|
||||
private boolean submittedRequests=false;
|
||||
|
||||
private ProcessDescriptor descriptor;
|
||||
private ProcessStatus status;
|
||||
|
||||
private String processId=UUID.randomUUID().toString();
|
||||
|
||||
private Queue<StepReport> queuedReports=new LinkedList<>();
|
||||
|
||||
|
||||
// private String folderId;
|
||||
|
||||
private WorkspaceFolderManager manager;
|
||||
|
||||
private Set<SyncOperationCallBack> toInvokeCallbacks=ConcurrentHashMap.newKeySet();
|
||||
|
||||
private CompletionCallback callback=null;
|
||||
|
||||
public Process(String folderId,CompletionCallback callback) throws WorkspaceInteractionException, InternalException {
|
||||
log.debug("Created Process with id {} ",processId);
|
||||
// this.folderId=folderId;
|
||||
manager=new WorkspaceFolderManager(folderId);
|
||||
manager.lock(processId);
|
||||
SynchFolderConfiguration folderConfig=manager.getSynchConfiguration();
|
||||
|
||||
try {
|
||||
descriptor=new ProcessDescriptor(folderId, manager.getTheFolder().getPath(),System.currentTimeMillis(),processId,folderConfig);
|
||||
}catch(Exception e) {
|
||||
throw new WorkspaceInteractionException("Unable to read path from folder "+folderId,e);
|
||||
}
|
||||
|
||||
this.callback=callback;
|
||||
|
||||
status=new ProcessStatus();
|
||||
}
|
||||
|
||||
|
||||
public void launch(ExecutorService service) throws WorkspaceNotSynchedException, WorkspaceInteractionException, InternalErrorException, InternalException {
|
||||
WorkspaceUtils.resetStatus(manager.getTheFolder());
|
||||
status.setCurrentMessage("Analyzing folder..");
|
||||
|
||||
generateRequests(this,service, manager.getTheFolder());
|
||||
submittedRequests=true;
|
||||
if(status.getQueuedTransfers().get()>0) {
|
||||
status.setCurrentMessage("Waiting for requests ["+status.getQueuedTransfers().get()+"] to be served.");
|
||||
status.setStatus(Status.ONGOING);
|
||||
while(!queuedReports.isEmpty()) {
|
||||
onStep(queuedReports.remove());
|
||||
}
|
||||
}else {
|
||||
status.setCurrentMessage("Folder is up to date.");
|
||||
status.setStatus(Status.COMPLETED);
|
||||
callback.onProcessCompleted(this);
|
||||
invokeCallbacks();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void addCallBack(SyncOperationCallBack toAddCallback) {
|
||||
toInvokeCallbacks.add(toAddCallback);
|
||||
log.debug("Added callback for process {}. Current callback size is {}",processId,toInvokeCallbacks.size());
|
||||
}
|
||||
|
||||
public ProcessDescriptor getDescriptor() {
|
||||
return descriptor;
|
||||
}
|
||||
|
||||
// signals from serving threads
|
||||
|
||||
public void onStep(StepReport report) {
|
||||
if(!submittedRequests) {
|
||||
queuedReports.add(report);
|
||||
}else {
|
||||
// serve
|
||||
updateStatus(report);
|
||||
if(isCompleted()) {
|
||||
try {
|
||||
manager.setLastUpdateTime();
|
||||
}catch(Throwable t) {
|
||||
log.error("Unable to update last update time.",t);
|
||||
}
|
||||
if(status.getStatus().equals(Status.WARNINGS))
|
||||
status.setCurrentMessage("Process completed with errors. Please check logs or retry.");
|
||||
else status.setCurrentMessage("Synchronization complete.");
|
||||
status.setStatus(Status.COMPLETED);
|
||||
callback.onProcessCompleted(this);
|
||||
}
|
||||
invokeCallbacks();
|
||||
}
|
||||
}
|
||||
|
||||
private void invokeCallbacks() {
|
||||
|
||||
for(SyncOperationCallBack callback:toInvokeCallbacks) {
|
||||
try {
|
||||
callback.onStep((ProcessStatus)status.clone(), (ProcessDescriptor)descriptor.clone());
|
||||
}catch(Throwable t) {
|
||||
log.warn("Unable to invoke callback {}.",callback,t);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
private boolean isCompleted() {
|
||||
return (status.getErrorCount().get()+status.getServedTransfers().get()>=status.getQueuedTransfers().get());
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
public void updateStatus(StepReport report) {
|
||||
log.debug("Logging report {} ",report);
|
||||
switch(report.getStatus()) {
|
||||
case CANCELLED :
|
||||
case ERROR:{
|
||||
status.getErrorCount().incrementAndGet();
|
||||
if(!status.getStatus().equals(Status.STOPPED))
|
||||
status.setStatus(Status.WARNINGS);
|
||||
break;
|
||||
}
|
||||
default : {
|
||||
status.getServedTransfers().incrementAndGet();
|
||||
break;
|
||||
}
|
||||
}
|
||||
status.getLogBuilder().append(
|
||||
String.format("%s - item [%s] %s: %s \n", Constants.DATE_FORMAT.format(new Date(report.getCompletionTime())),
|
||||
report.getElementName(),report.getStatus()+"",report.getMessage()));
|
||||
}
|
||||
|
||||
|
||||
|
||||
public ProcessStatus getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
public void cancel() {
|
||||
if(status.getQueuedTransfers().get()>1) {
|
||||
status.setStatus(Status.STOPPED);
|
||||
status.setCurrentMessage("Process Stopped. Waiting for remaining requests to cancel..");
|
||||
}else {
|
||||
status.setStatus(Status.COMPLETED);
|
||||
status.setCurrentMessage("Process cancelled before it started.");
|
||||
}
|
||||
invokeCallbacks();
|
||||
callback.onProcessCompleted(this);
|
||||
|
||||
}
|
||||
|
||||
public void cleanup() throws WorkspaceNotSynchedException, WorkspaceInteractionException, InternalException {
|
||||
manager.unlock(processId);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void finalize() throws Throwable {
|
||||
try {
|
||||
cleanup();
|
||||
}catch(Throwable t) {
|
||||
log.warn("Exception while trying to cleanup {} ",this);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static final void generateRequests(Process ownerProcess,ExecutorService service,WorkspaceFolder toScanFolder ) throws InternalErrorException, InternalException{
|
||||
|
||||
String folderPath=toScanFolder.getPath();
|
||||
|
||||
log.info("Generating requests for folder {}",folderPath);
|
||||
log.debug("Process is {} ",ownerProcess.getDescriptor());
|
||||
Set<String> handledWorkspaceItemEntries=new HashSet<String>();
|
||||
|
||||
SynchFolderConfiguration config=ownerProcess.getDescriptor().getSynchConfiguration();
|
||||
|
||||
Set<String> remoteChildrenNames;
|
||||
Set<String> localChildrenNames=new HashSet<>();
|
||||
|
||||
List<WorkspaceItem> localFolderChildren=toScanFolder.getChildren();
|
||||
for(WorkspaceItem item:localFolderChildren) {
|
||||
localChildrenNames.add(item.getName());
|
||||
}
|
||||
|
||||
String relativePath=toScanFolder.getProperties().getPropertyValue(Constants.WorkspaceProperties.REMOTE_PATH);
|
||||
ThreddsController folderController=new ThreddsController(relativePath,config.getTargetToken());
|
||||
|
||||
RemoteFileDescriptor folderDesc=null;
|
||||
try{
|
||||
folderDesc=folderController.getFileDescriptor();
|
||||
}catch(RemoteFileNotFoundException e) {
|
||||
log.debug("RemoteFolder {} doesn't exists. Creating it.. ",relativePath);
|
||||
folderController.createEmptyFolder(null);
|
||||
folderDesc=folderController.getFileDescriptor();
|
||||
}
|
||||
|
||||
remoteChildrenNames=new HashSet<>(folderDesc.getChildren());
|
||||
|
||||
|
||||
//*********************** HANDLING ACCOUNTING ENTRIES
|
||||
|
||||
Set<String> handledAccountingEntries=WorkspaceUtils.scanAccountingForStatus( toScanFolder, config, localChildrenNames, remoteChildrenNames, folderController, ownerProcess, service);
|
||||
|
||||
|
||||
|
||||
//SCAN FOLDER CONTENT
|
||||
log.debug("Checking content of {} ",folderPath);
|
||||
for(WorkspaceItem item:localFolderChildren) {
|
||||
|
||||
if(item.isFolder()) {
|
||||
// RECURSIVE ON SUB FOLDERS
|
||||
generateRequests(ownerProcess,service,(WorkspaceFolder) item);
|
||||
|
||||
}else {
|
||||
Map<String,String> props=item.getProperties().getProperties();
|
||||
String itemId=item.getId();
|
||||
String itemName=item.getName();
|
||||
|
||||
// REQUESTS ARE EVALUATED ON PROPERTIES (SET BY PREVIOUS SCAN)
|
||||
|
||||
if(props.containsKey(Constants.WorkspaceProperties.TBS)&&(props.get(Constants.WorkspaceProperties.TBS)!=null)) {
|
||||
try {
|
||||
SynchronizationStatus status=SynchronizationStatus.valueOf(props.get(Constants.WorkspaceProperties.SYNCHRONIZATION_STATUS));
|
||||
log.trace("Found TBS item {}, name {}, status : ",item.getId(),item.getName(),status);
|
||||
SynchronizationRequest request=null;
|
||||
|
||||
switch(status) {
|
||||
case OUTDATED_REMOTE : request= new TransferToThreddsRequest(ownerProcess,toScanFolder,item);
|
||||
break;
|
||||
case OUTDATED_WS : request = new TransferFromThreddsRequest(ownerProcess, item, toScanFolder, null);
|
||||
break;
|
||||
|
||||
}
|
||||
if(request!=null) {
|
||||
// KEEP TRACK OF HANDLED ITEMS & LAUNCH
|
||||
service.execute(new SynchronizationThread(request));
|
||||
log.debug("Submitted request number {} ",ownerProcess.status.getQueuedTransfers().incrementAndGet());
|
||||
}else log.debug("Item is up to date");
|
||||
handledWorkspaceItemEntries.add(itemName);
|
||||
}catch(Throwable t) {
|
||||
log.error("Unable to submit request for {} ID {} ",itemName,itemId,t);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// check items to be imported
|
||||
|
||||
try {
|
||||
Set<String> toImportItems=WorkspaceUtils.scanRemoteFolder(folderDesc, handledAccountingEntries, handledWorkspaceItemEntries, toScanFolder, folderController, config, ownerProcess, service);
|
||||
log.debug("Checking if remote location contains folders to be imported...");
|
||||
for(String item:toImportItems) {
|
||||
if(folderController.getFileDescriptor(item).isDirectory()) {
|
||||
log.info("Creating folder {} under {} ",item,folderPath);
|
||||
try{
|
||||
WorkspaceFolder folder=toScanFolder.createFolder(item, "Imported from thredds");
|
||||
WorkspaceUtils.initProperties(folder,relativePath+"/"+item , config.getFilter(), config.getTargetToken(),config.getToCreateCatalogName(),config.getValidateMetadata(),config.getRootFolderId());
|
||||
generateRequests(ownerProcess, service, folder);
|
||||
}catch(Throwable t) {
|
||||
log.error("Unable to import folder {} into {} ",item,folderPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
}catch(InternalException e) {
|
||||
log.error("Unable to check remote content with config {} ",config,e);
|
||||
}
|
||||
|
||||
|
||||
log.info("All requests for {} synchronization have been submitted [count {} ]. ",folderPath,ownerProcess.status.getQueuedTransfers().get());
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
package org.gcube.usecases.ws.thredds.engine.impl;
|
||||
|
||||
import org.gcube.usecases.ws.thredds.model.SynchFolderConfiguration;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
public class ProcessDescriptor implements Cloneable{
|
||||
|
||||
private String folderId;
|
||||
private String folderPath;
|
||||
private long launchTime;
|
||||
private String processId;
|
||||
|
||||
private SynchFolderConfiguration synchConfiguration;
|
||||
|
||||
@Override
|
||||
protected Object clone() throws CloneNotSupportedException {
|
||||
return super.clone();
|
||||
}
|
||||
}
|
@ -0,0 +1,50 @@
|
||||
package org.gcube.usecases.ws.thredds.engine.impl;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
|
||||
|
||||
public class ProcessStatus implements Cloneable{
|
||||
|
||||
public static enum Status{
|
||||
INITIALIZING, // initial status
|
||||
ONGOING, // synch in progress
|
||||
WARNINGS, // errors occurred, still WORKING
|
||||
STOPPED, // STOP received, waiting for request to finish
|
||||
COMPLETED // FINISHED PROCESS
|
||||
}
|
||||
|
||||
|
||||
private AtomicLong queuedTransfers=new AtomicLong(0);
|
||||
private AtomicLong servedTransfers=new AtomicLong(0);
|
||||
private AtomicLong errorCount=new AtomicLong(0);
|
||||
private Status status=Status.INITIALIZING;
|
||||
|
||||
private StringBuilder logBuilder=new StringBuilder();
|
||||
|
||||
private String currentMessage="Waiting to start..";
|
||||
|
||||
@Override
|
||||
protected Object clone() throws CloneNotSupportedException {
|
||||
return super.clone();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ProcessStatus [queuedTransfers=" + queuedTransfers + ", servedTransfers=" + servedTransfers
|
||||
+ ", errorCount=" + errorCount + ", status=" + status + ", currentMessage=" + currentMessage + "]";
|
||||
}
|
||||
|
||||
public float getPercent() {
|
||||
switch(status) {
|
||||
case INITIALIZING : return 0;
|
||||
case COMPLETED : return 1;
|
||||
default : return queuedTransfers.get()==0?0:((float)(servedTransfers.get()+errorCount.get()))/queuedTransfers.get();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,267 @@
|
||||
package org.gcube.usecases.ws.thredds.engine.impl;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.LinkedBlockingDeque;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.gcube.data.transfer.model.plugins.thredds.DataSetScan;
|
||||
import org.gcube.data.transfer.model.plugins.thredds.ThreddsCatalog;
|
||||
import org.gcube.data.transfer.model.plugins.thredds.ThreddsInfo;
|
||||
import org.gcube.usecases.ws.thredds.Constants;
|
||||
import org.gcube.usecases.ws.thredds.LocalConfiguration;
|
||||
import org.gcube.usecases.ws.thredds.SyncEngine;
|
||||
import org.gcube.usecases.ws.thredds.engine.impl.threads.ProcessInitializationThread;
|
||||
import org.gcube.usecases.ws.thredds.engine.impl.threads.RequestLogger;
|
||||
import org.gcube.usecases.ws.thredds.faults.InternalException;
|
||||
import org.gcube.usecases.ws.thredds.faults.ProcessNotFoundException;
|
||||
import org.gcube.usecases.ws.thredds.faults.WorkspaceFolderNotRootException;
|
||||
import org.gcube.usecases.ws.thredds.faults.WorkspaceInteractionException;
|
||||
import org.gcube.usecases.ws.thredds.faults.WorkspaceLockedException;
|
||||
import org.gcube.usecases.ws.thredds.faults.WorkspaceNotSynchedException;
|
||||
import org.gcube.usecases.ws.thredds.model.CompletionCallback;
|
||||
import org.gcube.usecases.ws.thredds.model.SyncFolderDescriptor;
|
||||
import org.gcube.usecases.ws.thredds.model.SyncOperationCallBack;
|
||||
import org.gcube.usecases.ws.thredds.model.SynchFolderConfiguration;
|
||||
import org.gcube.usecases.ws.thredds.model.SynchronizedElementInfo;
|
||||
import org.gcube.usecases.ws.thredds.model.gui.CatalogBean;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Slf4j
|
||||
public class SynchEngineImpl implements SyncEngine{
|
||||
|
||||
private static SynchEngineImpl instance=null;
|
||||
|
||||
|
||||
public static synchronized SyncEngine get() {
|
||||
if(instance==null) {
|
||||
instance=new SynchEngineImpl();
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
|
||||
private SynchEngineImpl() {
|
||||
|
||||
localProcesses=new ConcurrentHashMap<>();
|
||||
|
||||
int scannerMaxSize=Integer.parseInt(LocalConfiguration.getProperty(Constants.Configuration.SCANNER_POOL_MAX_SIZE));
|
||||
int scannerCoreSize=Integer.parseInt(LocalConfiguration.getProperty(Constants.Configuration.SCANNER_POOL_CORE_SIZE));
|
||||
int scannerIdleMs=Integer.parseInt(LocalConfiguration.getProperty(Constants.Configuration.SCANNER_POOL_IDLE_MS));
|
||||
|
||||
|
||||
int transfersMaxSize=Integer.parseInt(LocalConfiguration.getProperty(Constants.Configuration.TRANSFERS_POOL_MAX_SIZE));
|
||||
int transfersCoreSize=Integer.parseInt(LocalConfiguration.getProperty(Constants.Configuration.TRANSFERS_POOL_CORE_SIZE));
|
||||
int transfersIdleMs=Integer.parseInt(LocalConfiguration.getProperty(Constants.Configuration.TRANSFERS_POOL_IDLE_MS));
|
||||
|
||||
initializationExecutor= new ThreadPoolExecutor(scannerCoreSize, scannerMaxSize, scannerIdleMs,
|
||||
TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>());
|
||||
|
||||
synchronizationExecutor=new ThreadPoolExecutor(transfersCoreSize, transfersMaxSize, transfersIdleMs,
|
||||
TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>());
|
||||
}
|
||||
|
||||
|
||||
private String requestLoggerPath=null;
|
||||
|
||||
@Override
|
||||
public void setRequestLogger(String path) {
|
||||
requestLoggerPath=path;
|
||||
}
|
||||
@Override
|
||||
public boolean isRequestLoggerEnabled() {
|
||||
return requestLoggerPath!=null;
|
||||
}
|
||||
@Override
|
||||
public String getRequestLoggerPath() {
|
||||
return requestLoggerPath;
|
||||
}
|
||||
|
||||
|
||||
//folder ID -> Process
|
||||
private ConcurrentHashMap<String, Process> localProcesses;
|
||||
|
||||
|
||||
private ExecutorService initializationExecutor=null;
|
||||
|
||||
private ExecutorService synchronizationExecutor=null;
|
||||
|
||||
|
||||
private final CompletionCallback completionCallback=new CompletionCallback() {
|
||||
|
||||
@Override
|
||||
public void onProcessCompleted(Process completedProcess) {
|
||||
try {
|
||||
ProcessDescriptor descriptor=completedProcess.getDescriptor();
|
||||
log.info("Process {} is completed. Going to cleanup.. ",descriptor);
|
||||
localProcesses.remove(descriptor.getFolderId());
|
||||
completedProcess.cleanup();
|
||||
}catch(Throwable t) {
|
||||
log.warn("Unable to cleanup {} ",completedProcess,t);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public SyncFolderDescriptor check(String folderId, boolean recursively) throws WorkspaceInteractionException, InternalException {
|
||||
WorkspaceFolderManager manager=new WorkspaceFolderManager(folderId);
|
||||
return manager.check(recursively);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerCallBack(String folderId, SyncOperationCallBack callback) throws ProcessNotFoundException {
|
||||
if(!localProcesses.containsKey(folderId)) throw new ProcessNotFoundException(folderId+" is not under local processes");
|
||||
localProcesses.get(folderId).addCallBack(callback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProcessDescriptor doSync(String folderId) throws WorkspaceInteractionException, InternalException {
|
||||
if(localProcesses.containsKey(folderId))
|
||||
return localProcesses.get(folderId).getDescriptor();
|
||||
else {
|
||||
WorkspaceFolderManager manager=new WorkspaceFolderManager(folderId);
|
||||
if (!manager.isSynched()) throw new WorkspaceNotSynchedException("Folder "+folderId+" is not configured for synchronization.");
|
||||
if(manager.isLocked()) throw new WorkspaceLockedException("Folder "+folderId+"is locked by an external process.");
|
||||
if(!manager.isRoot()) throw new WorkspaceFolderNotRootException("Unable to launch synch operation. Folder "+folderId+" is not root configuration");
|
||||
Process toLaunch=new Process(folderId,completionCallback);
|
||||
localProcesses.put(folderId, toLaunch);
|
||||
initializationExecutor.submit(new ProcessInitializationThread(toLaunch,synchronizationExecutor));
|
||||
return toLaunch.getDescriptor();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stopSynch(String folderId) throws ProcessNotFoundException {
|
||||
if(!localProcesses.containsKey(folderId)) throw new ProcessNotFoundException(folderId+" is not under local processes");
|
||||
localProcesses.get(folderId).cancel();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void setSynchronizedFolder(SynchFolderConfiguration config,String folderId) throws WorkspaceInteractionException, InternalException {
|
||||
|
||||
// Check config
|
||||
if(config==null) throw new InternalException("Passed config is null : "+config);
|
||||
String remotePath=config.getRemotePath();
|
||||
if(remotePath==null||remotePath.isEmpty()||remotePath.startsWith("/"))
|
||||
throw new InternalException("Invalid remote path "+remotePath+".");
|
||||
|
||||
new WorkspaceFolderManager(folderId).configure(config);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unsetSynchronizedFolder(String folderId,boolean deleteRemoteContent) throws WorkspaceInteractionException, InternalException {
|
||||
new WorkspaceFolderManager(folderId).dismiss(deleteRemoteContent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SynchronizedElementInfo getInfo(String elementId) {
|
||||
return WorkspaceFolderManager.getInfo(elementId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateCatalogFile(String folderId, File toUpdate) throws InternalException {
|
||||
File previousCatalogFile=null;
|
||||
try {
|
||||
WorkspaceFolderManager manager=new WorkspaceFolderManager(folderId);
|
||||
previousCatalogFile=manager.loadCatalogFile();
|
||||
String lockId=UUID.randomUUID().toString();
|
||||
manager.lock(lockId);
|
||||
manager.updateCatalogFile(toUpdate);
|
||||
manager.unlock(lockId);
|
||||
}catch(Throwable t) {
|
||||
log.warn("Unable to update catalogFile for {}. Trying to restore previous one..",folderId,t);
|
||||
throw new InternalException("Unable to restore previous catalog.",t);
|
||||
//TODO try to restore previous catalog
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void shutDown() {
|
||||
log.trace("Cancelling processes...");
|
||||
for(Entry<String,Process> entry:localProcesses.entrySet())
|
||||
entry.getValue().cancel();
|
||||
|
||||
log.trace("Shutting down services... ");
|
||||
initializationExecutor.shutdown();
|
||||
synchronizationExecutor.shutdown();
|
||||
|
||||
do {
|
||||
log.trace("Waiting for services to terminate..");
|
||||
try {Thread.sleep(1000l);
|
||||
} catch (InterruptedException e) {}
|
||||
}while(!initializationExecutor.isTerminated()||!synchronizationExecutor.isTerminated());
|
||||
|
||||
RequestLogger.get().close();
|
||||
log.trace("Terminated.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void forceUnlock(String folderId) throws InternalException, WorkspaceInteractionException {
|
||||
log.warn("Forcing unlock of {} ",folderId);
|
||||
new WorkspaceFolderManager(folderId).forceUnlock();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public ProcessDescriptor getProcessDescriptorByFolderId(String folderId) throws ProcessNotFoundException {
|
||||
if(!localProcesses.containsKey(folderId)) throw new ProcessNotFoundException(folderId+" is not under processes or process is not in this host");
|
||||
return localProcesses.get(folderId).getDescriptor();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProcessStatus getProcessStatusByFolderId(String folderId) throws ProcessNotFoundException {
|
||||
if(!localProcesses.containsKey(folderId)) throw new ProcessNotFoundException(folderId+" is not under processes or process is not in this host");
|
||||
return localProcesses.get(folderId).getStatus();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Set<CatalogBean> getAvailableCatalogsByToken(String token) throws InternalException {
|
||||
ThreddsController controller=new ThreddsController("",token);
|
||||
ThreddsInfo info=controller.getThreddsInfo();
|
||||
Set<CatalogBean> toReturn=asCatalogBeanSet(info.getCatalog());
|
||||
DataSetScan mainScan=info.getCatalog().getDeclaredDataSetScan().iterator().next();
|
||||
CatalogBean defaultBean=new CatalogBean(mainScan.getName(),mainScan.getLocation(),true);
|
||||
toReturn.remove(defaultBean);
|
||||
toReturn.add(defaultBean);
|
||||
|
||||
//*** Cleaning :
|
||||
// absolute paths to relative paths (from thredds persistence)
|
||||
// leading/ending '/'
|
||||
String threddsPersistencePath=info.getLocalBasePath();
|
||||
for(CatalogBean bean:toReturn) {
|
||||
String path=bean.getPath();
|
||||
if(path.startsWith(threddsPersistencePath))
|
||||
path=path.substring(threddsPersistencePath.length());
|
||||
if(path.startsWith("/")) path=path.substring(1);
|
||||
if(path.endsWith("/"))path=path.substring(0, path.length()-1);
|
||||
bean.setPath(path);
|
||||
}
|
||||
|
||||
|
||||
return toReturn;
|
||||
}
|
||||
|
||||
private static HashSet<CatalogBean> asCatalogBeanSet(ThreddsCatalog catalog){
|
||||
HashSet<CatalogBean> toReturn=new HashSet<>();
|
||||
for(DataSetScan scan:catalog.getDeclaredDataSetScan())
|
||||
toReturn.add(new CatalogBean(scan.getName(),
|
||||
scan.getLocation(),false));
|
||||
if(catalog.getSubCatalogs()!=null&&catalog.getSubCatalogs().getLinkedCatalogs()!=null)
|
||||
for(ThreddsCatalog sub:catalog.getSubCatalogs().getLinkedCatalogs())
|
||||
toReturn.addAll(asCatalogBeanSet(sub));
|
||||
return toReturn;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,318 @@
|
||||
package org.gcube.usecases.ws.thredds.engine.impl;
|
||||
|
||||
import static org.gcube.resources.discovery.icclient.ICFactory.clientFor;
|
||||
import static org.gcube.resources.discovery.icclient.ICFactory.queryFor;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.PrintWriter;
|
||||
import java.nio.file.Files;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.ws.rs.client.Client;
|
||||
import javax.ws.rs.client.ClientBuilder;
|
||||
import javax.ws.rs.client.WebTarget;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.Response;
|
||||
|
||||
import org.apache.tika.io.IOUtils;
|
||||
import org.gcube.common.resources.gcore.GCoreEndpoint;
|
||||
import org.gcube.data.transfer.library.DataTransferClient;
|
||||
import org.gcube.data.transfer.library.TransferResult;
|
||||
import org.gcube.data.transfer.library.client.AuthorizationFilter;
|
||||
import org.gcube.data.transfer.library.faults.DestinationNotSetException;
|
||||
import org.gcube.data.transfer.library.faults.FailedTransferException;
|
||||
import org.gcube.data.transfer.library.faults.InitializationException;
|
||||
import org.gcube.data.transfer.library.faults.InvalidDestinationException;
|
||||
import org.gcube.data.transfer.library.faults.InvalidSourceException;
|
||||
import org.gcube.data.transfer.library.faults.ServiceNotFoundException;
|
||||
import org.gcube.data.transfer.library.faults.SourceNotSetException;
|
||||
import org.gcube.data.transfer.library.faults.UnreachableNodeException;
|
||||
import org.gcube.data.transfer.model.Destination;
|
||||
import org.gcube.data.transfer.model.DestinationClashPolicy;
|
||||
import org.gcube.data.transfer.model.PluginInvocation;
|
||||
import org.gcube.data.transfer.model.RemoteFileDescriptor;
|
||||
import org.gcube.data.transfer.model.plugins.thredds.ThreddsCatalog;
|
||||
import org.gcube.data.transfer.model.plugins.thredds.ThreddsInfo;
|
||||
import org.gcube.resources.discovery.client.api.DiscoveryClient;
|
||||
import org.gcube.resources.discovery.client.queries.api.SimpleQuery;
|
||||
import org.gcube.spatial.data.sdi.model.ServiceConstants;
|
||||
import org.gcube.spatial.data.sdi.utils.ScopeUtils;
|
||||
import org.gcube.usecases.ws.thredds.Constants;
|
||||
import org.gcube.usecases.ws.thredds.TokenSetter;
|
||||
import org.gcube.usecases.ws.thredds.faults.InternalException;
|
||||
import org.gcube.usecases.ws.thredds.faults.RemoteFileNotFoundException;
|
||||
import org.gcube.usecases.ws.thredds.faults.UnableToLockException;
|
||||
import org.glassfish.jersey.client.ClientConfig;
|
||||
import org.glassfish.jersey.client.ClientProperties;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Slf4j
|
||||
public class ThreddsController {
|
||||
|
||||
private String hostname;
|
||||
private String operatingPath;
|
||||
private String targetToken;
|
||||
|
||||
public ThreddsController(String path,String targetToken) throws InternalException {
|
||||
operatingPath=path;
|
||||
this.targetToken=targetToken;
|
||||
setTargetToken();
|
||||
hostname=getThreddsHost();
|
||||
if(hostname==null) throw new InternalException("Unable to find a thredds instance in target scope "+ScopeUtils.getCurrentScope());
|
||||
resetCallerToken();
|
||||
}
|
||||
|
||||
private static final String truncate(String toTruncate) {
|
||||
return toTruncate==null?toTruncate:toTruncate.substring(0, toTruncate.length()/2)+"...";
|
||||
}
|
||||
|
||||
private String callerToken=null;
|
||||
|
||||
private void setTargetToken() {
|
||||
if(callerToken==null) {
|
||||
callerToken=TokenSetter.getCurrentToken();
|
||||
log.trace("Storing caller token {}. Target Token is {}",truncate(callerToken),truncate(targetToken));
|
||||
TokenSetter.setToken(targetToken);
|
||||
}else {
|
||||
log.trace("Caller token {} already registered. Target Token is {}",truncate(callerToken),truncate(targetToken));
|
||||
}
|
||||
}
|
||||
|
||||
private void resetCallerToken() {
|
||||
if(callerToken!=null) {
|
||||
log.trace("Resetting caller token {}. Target Token is {}, current is {} ",truncate(callerToken),truncate(targetToken),truncate(TokenSetter.getCurrentToken()));
|
||||
TokenSetter.setToken(callerToken);
|
||||
callerToken=null;
|
||||
}else log.trace("Caller token {} already reset [current token {}]. Target Token is {}",truncate(callerToken),truncate(TokenSetter.getCurrentToken()),truncate(targetToken));
|
||||
}
|
||||
|
||||
public final ThreddsInfo getThreddsInfo() {
|
||||
setTargetToken();
|
||||
try{
|
||||
String infoPath="https://"+hostname+"/data-transfer-service/gcube/service/Capabilities/pluginInfo/REGISTER_CATALOG";;
|
||||
log.info("Loading thredds info from {} ",infoPath);
|
||||
WebTarget target=getWebClient().target(infoPath);
|
||||
return target.request(MediaType.APPLICATION_JSON).get(ThreddsInfo.class);
|
||||
}finally {
|
||||
resetCallerToken();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void lockFolder(String processId) throws UnableToLockException {
|
||||
setTargetToken();
|
||||
PrintWriter writer=null;
|
||||
File temp=null;
|
||||
try{
|
||||
log.info("Locking remote path {} to processId {} ",operatingPath,processId);
|
||||
DataTransferClient cl=getDTClient(hostname);
|
||||
|
||||
Destination dest=new Destination();
|
||||
dest.setCreateSubfolders(true);
|
||||
dest.setOnExistingFileName(DestinationClashPolicy.FAIL);
|
||||
dest.setOnExistingSubFolder(DestinationClashPolicy.APPEND);
|
||||
dest.setPersistenceId(Constants.THREDDS_PERSISTENCE);
|
||||
dest.setSubFolder(operatingPath);
|
||||
dest.setDestinationFileName(Constants.LOCK_FILE);
|
||||
|
||||
temp=File.createTempFile("tmp_lock", ".tmp");
|
||||
writer=new PrintWriter(temp);
|
||||
writer.write(processId);
|
||||
writer.flush();
|
||||
writer.close();
|
||||
|
||||
cl.localFile(temp, dest);
|
||||
}catch(Throwable t) {
|
||||
throw new UnableToLockException("Unable to lock "+operatingPath,t);
|
||||
}finally {
|
||||
if(writer!=null) IOUtils.closeQuietly(writer);
|
||||
if(temp!=null)try {
|
||||
Files.deleteIfExists(temp.toPath());
|
||||
}catch(IOException e) {
|
||||
log.warn("Unable to delete temp file {} ",temp.getAbsolutePath(),e);
|
||||
}
|
||||
resetCallerToken();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void deleteThreddsFile(String location) throws RemoteFileNotFoundException {
|
||||
setTargetToken();
|
||||
String urlString="http://"+hostname+":80/"+Constants.THREDDS_DATA_TRANSFER_BASE_URL+getPathFromStartingLocation(location);
|
||||
log.info("Deleting file at {} ",urlString);
|
||||
try{
|
||||
getWebClient().target(urlString).request().delete();
|
||||
}catch(Throwable t) {
|
||||
throw new RemoteFileNotFoundException("Unable to access "+urlString, t);
|
||||
}finally{
|
||||
resetCallerToken();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public boolean existsThreddsFile(String location) {
|
||||
try{
|
||||
getFileDescriptor(location);
|
||||
return true;
|
||||
}catch(RemoteFileNotFoundException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public String readThreddsFile(String location) throws RemoteFileNotFoundException {
|
||||
setTargetToken();
|
||||
String urlString="http://"+hostname+":80/"+Constants.THREDDS_DATA_TRANSFER_BASE_URL+getPathFromStartingLocation(location);
|
||||
log.info("Reading file at {} ",urlString);
|
||||
try{
|
||||
return getWebClient().target(urlString).request().get().readEntity(String.class);
|
||||
}catch(Throwable t) {
|
||||
throw new RemoteFileNotFoundException("Unable to access "+urlString, t);
|
||||
}finally {
|
||||
resetCallerToken();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void createEmptyFolder(String targetPath) throws InternalException {
|
||||
setTargetToken();
|
||||
String toCleanPath=getPathFromStartingLocation(targetPath);
|
||||
try{
|
||||
log.info("Cleaning up {} on {} ",toCleanPath,hostname);
|
||||
DataTransferClient client=getDTClient(hostname);
|
||||
File toTransfer=File.createTempFile("clean", ".dt_temp");
|
||||
toTransfer.createNewFile();
|
||||
Destination dest=new Destination();
|
||||
dest.setCreateSubfolders(true);
|
||||
dest.setOnExistingFileName(DestinationClashPolicy.REWRITE);
|
||||
dest.setOnExistingSubFolder(DestinationClashPolicy.REWRITE);
|
||||
dest.setPersistenceId(Constants.THREDDS_PERSISTENCE);
|
||||
dest.setSubFolder(toCleanPath);
|
||||
dest.setDestinationFileName(toTransfer.getName());
|
||||
|
||||
log.info("Going to cleanup remote folder {} on {} ",dest.getSubFolder(),hostname);
|
||||
client.localFile(toTransfer, dest);
|
||||
this.deleteThreddsFile(targetPath+"/"+toTransfer.getName());
|
||||
log.info("Done");
|
||||
log.debug("Resulting folder descriptor : {} ",getFileDescriptor(targetPath));
|
||||
}catch(Exception e) {
|
||||
log.error("Unable to delete remote folder "+toCleanPath,e);
|
||||
throw new InternalException("Unable to cleanup remote folder.");
|
||||
}finally {
|
||||
resetCallerToken();
|
||||
}
|
||||
}
|
||||
|
||||
public ThreddsCatalog createCatalog(String name) throws InternalException {
|
||||
setTargetToken();
|
||||
try{
|
||||
log.info("Creating catalog with name {} for path {} ",name,operatingPath);
|
||||
String sdiUrl="http://"+getSDIServiceHost()+"/"+Constants.SDI_THREDDS_BASE_URL;
|
||||
Response resp=getWebClient().target(sdiUrl).
|
||||
queryParam("name", name).
|
||||
queryParam("path", operatingPath).
|
||||
queryParam("folder", operatingPath).request().put(null);
|
||||
if(!(resp.getStatus()>=200&&resp.getStatus()<300))
|
||||
throw new InternalException("Failed catalog registration on SDI Service. Message "+resp.readEntity(String.class));
|
||||
return getCatalog();
|
||||
}catch(Throwable t) {
|
||||
log.error("Unable to create catalog",t);
|
||||
throw new InternalException("Unable to create catalog",t);
|
||||
}finally {
|
||||
resetCallerToken();
|
||||
}
|
||||
}
|
||||
|
||||
public ThreddsCatalog getCatalog() {
|
||||
setTargetToken();
|
||||
try{ThreddsInfo info=getThreddsInfo();
|
||||
String instanceBasePath=info.getLocalBasePath();
|
||||
return info.getCatalogByFittingLocation(instanceBasePath+"/"+operatingPath);
|
||||
}finally {
|
||||
resetCallerToken();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public RemoteFileDescriptor getFileDescriptor() throws RemoteFileNotFoundException {
|
||||
return getFileDescriptor(null);
|
||||
}
|
||||
|
||||
public RemoteFileDescriptor getFileDescriptor(String path) throws RemoteFileNotFoundException {
|
||||
setTargetToken();
|
||||
String urlString="http://"+hostname+":80/"+Constants.THREDDS_DATA_TRANSFER_BASE_URL+getPathFromStartingLocation(path);
|
||||
log.info("Reading file at {} ",urlString);
|
||||
try{
|
||||
return getWebClient().target(urlString).queryParam("descriptor", true).request().get().readEntity(RemoteFileDescriptor.class);
|
||||
}catch(Throwable t) {
|
||||
throw new RemoteFileNotFoundException("Unable to access "+urlString, t);
|
||||
}finally {
|
||||
resetCallerToken();
|
||||
}
|
||||
}
|
||||
|
||||
public InputStream getInputStream(String path) throws RemoteFileNotFoundException {
|
||||
setTargetToken();
|
||||
String urlString="http://"+hostname+":80/"+Constants.THREDDS_DATA_TRANSFER_BASE_URL+getPathFromStartingLocation(path);
|
||||
log.info("Reading file at {} ",urlString);
|
||||
try{
|
||||
return getWebClient().target(urlString).request().get().readEntity(InputStream.class);
|
||||
}catch(Throwable t) {
|
||||
throw new RemoteFileNotFoundException("Unable to access "+urlString, t);
|
||||
}finally {
|
||||
resetCallerToken();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public TransferResult transferFile(Destination dest,String url,Set<PluginInvocation> invocations) throws InvalidSourceException, SourceNotSetException, FailedTransferException, InitializationException, InvalidDestinationException, DestinationNotSetException {
|
||||
setTargetToken();
|
||||
try{DataTransferClient client=getDTClient(hostname);
|
||||
if(invocations!=null&&!invocations.isEmpty())
|
||||
return client.httpSource(url, dest,invocations);
|
||||
else return client.httpSource(url, dest);
|
||||
}finally {
|
||||
resetCallerToken();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private String getPathFromStartingLocation(String location) {
|
||||
if(location!=null&&location.length()>0)return operatingPath+"/"+location;
|
||||
else return operatingPath;
|
||||
}
|
||||
|
||||
private static String getSDIServiceHost(){
|
||||
return getGCoreEndpointHostname(ServiceConstants.SERVICE_CLASS, ServiceConstants.SERVICE_NAME);
|
||||
}
|
||||
|
||||
|
||||
private static String getThreddsHost(){
|
||||
return getGCoreEndpointHostname(ServiceConstants.SERVICE_CLASS, "Thredds");
|
||||
}
|
||||
|
||||
private static String getGCoreEndpointHostname(String serviceClass,String serviceName) {
|
||||
SimpleQuery query =queryFor(GCoreEndpoint.class);
|
||||
query.addCondition("$resource/Profile/ServiceClass/text() eq '"+serviceClass+"'")
|
||||
.addCondition("$resource/Profile/ServiceName/text() eq '"+serviceName+"'");
|
||||
// .setResult("$resource/Profile/AccessPoint");
|
||||
|
||||
DiscoveryClient<GCoreEndpoint> client = clientFor(GCoreEndpoint.class);
|
||||
|
||||
GCoreEndpoint endpoint= client.submit(query).get(0);
|
||||
|
||||
return endpoint.profile().endpoints().iterator().next().uri().getHost();
|
||||
}
|
||||
|
||||
private static Client getWebClient() {
|
||||
return ClientBuilder.newClient(new ClientConfig().register(AuthorizationFilter.class))
|
||||
.property(ClientProperties.SUPPRESS_HTTP_COMPLIANCE_VALIDATION, true);
|
||||
}
|
||||
|
||||
private static DataTransferClient getDTClient(String threddsHostName) throws UnreachableNodeException, ServiceNotFoundException {
|
||||
log.debug("Getting DT Client for {} ",threddsHostName);
|
||||
return DataTransferClient.getInstanceByEndpoint("http://"+threddsHostName+":80");
|
||||
}
|
||||
}
|
@ -0,0 +1,351 @@
|
||||
package org.gcube.usecases.ws.thredds.engine.impl;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.gcube.common.homelibrary.home.HomeLibrary;
|
||||
import org.gcube.common.homelibrary.home.exceptions.HomeNotFoundException;
|
||||
import org.gcube.common.homelibrary.home.exceptions.InternalErrorException;
|
||||
import org.gcube.common.homelibrary.home.exceptions.UserNotFoundException;
|
||||
import org.gcube.common.homelibrary.home.workspace.Workspace;
|
||||
import org.gcube.common.homelibrary.home.workspace.WorkspaceFolder;
|
||||
import org.gcube.common.homelibrary.home.workspace.WorkspaceItem;
|
||||
import org.gcube.common.homelibrary.home.workspace.exceptions.WorkspaceException;
|
||||
import org.gcube.data.transfer.model.RemoteFileDescriptor;
|
||||
import org.gcube.data.transfer.model.plugins.thredds.ThreddsCatalog;
|
||||
import org.gcube.usecases.ws.thredds.Constants;
|
||||
import org.gcube.usecases.ws.thredds.engine.impl.threads.ProcessIdProvider;
|
||||
import org.gcube.usecases.ws.thredds.faults.InternalException;
|
||||
import org.gcube.usecases.ws.thredds.faults.LockNotOwnedException;
|
||||
import org.gcube.usecases.ws.thredds.faults.RemoteFileNotFoundException;
|
||||
import org.gcube.usecases.ws.thredds.faults.WorkspaceInteractionException;
|
||||
import org.gcube.usecases.ws.thredds.faults.WorkspaceLockedException;
|
||||
import org.gcube.usecases.ws.thredds.faults.WorkspaceNotSynchedException;
|
||||
import org.gcube.usecases.ws.thredds.model.SyncFolderDescriptor;
|
||||
import org.gcube.usecases.ws.thredds.model.SynchFolderConfiguration;
|
||||
import org.gcube.usecases.ws.thredds.model.SynchronizedElementInfo;
|
||||
import org.gcube.usecases.ws.thredds.model.SynchronizedElementInfo.SynchronizationStatus;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Slf4j
|
||||
public class WorkspaceFolderManager {
|
||||
|
||||
|
||||
|
||||
public static SynchronizedElementInfo getInfo(String elementId) {
|
||||
// TODO FILL THIS
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
private WorkspaceFolder theFolder;
|
||||
|
||||
|
||||
private String folderId;
|
||||
|
||||
// Cahced objects
|
||||
private SynchFolderConfiguration config=null;
|
||||
private ThreddsController threddsController=null;
|
||||
|
||||
private Workspace ws;
|
||||
|
||||
public WorkspaceFolderManager(String folderId) throws WorkspaceInteractionException {
|
||||
try{
|
||||
ws = HomeLibrary.getHomeManagerFactory().getHomeManager().getHome().getWorkspace();
|
||||
theFolder=(WorkspaceFolder) ws.getItem(folderId);
|
||||
this.folderId=folderId;
|
||||
}catch(WorkspaceException | InternalErrorException | HomeNotFoundException | UserNotFoundException e) {
|
||||
throw new WorkspaceInteractionException("Unable to access folder id "+folderId,e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public WorkspaceFolder getTheFolder() {
|
||||
return theFolder;
|
||||
}
|
||||
|
||||
public ThreddsController getThreddsController() throws WorkspaceNotSynchedException, WorkspaceInteractionException, InternalException {
|
||||
if(threddsController==null) {
|
||||
SynchFolderConfiguration config=getSynchConfiguration();
|
||||
threddsController=new ThreddsController(config.getRemotePath(),config.getTargetToken());
|
||||
}
|
||||
return threddsController;
|
||||
}
|
||||
|
||||
private ThreddsController getRootThreddsController() throws WorkspaceNotSynchedException, WorkspaceInteractionException, InternalException {
|
||||
try {
|
||||
WorkspaceFolder root=(WorkspaceFolder) ws.getItem(getSynchConfiguration().getRootFolderId());
|
||||
SynchFolderConfiguration rootConfig=WorkspaceUtils.loadConfiguration(root);
|
||||
return new ThreddsController(rootConfig.getRemotePath(),rootConfig.getTargetToken());
|
||||
}catch(WorkspaceException | InternalErrorException e) {
|
||||
throw new WorkspaceInteractionException(e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public boolean isRoot() throws WorkspaceNotSynchedException, WorkspaceInteractionException{
|
||||
try{
|
||||
return getSynchConfiguration().getRootFolderId().equals(theFolder.getId());
|
||||
}catch(InternalErrorException e) {
|
||||
throw new WorkspaceInteractionException(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public SynchFolderConfiguration getSynchConfiguration() throws WorkspaceInteractionException, WorkspaceNotSynchedException {
|
||||
if(config==null) {
|
||||
try {
|
||||
if(!isSynched()) throw new WorkspaceNotSynchedException("Folder "+folderId+" is not synched.");
|
||||
log.debug("Loading properties for ");
|
||||
config=WorkspaceUtils.loadConfiguration(theFolder);
|
||||
}catch(InternalErrorException e) {
|
||||
throw new WorkspaceInteractionException("Unable to load synch configuration in "+folderId,e);
|
||||
}
|
||||
}
|
||||
return config;
|
||||
}
|
||||
|
||||
public boolean isSynched() throws WorkspaceInteractionException {
|
||||
try{
|
||||
Map<String,String> props=theFolder.getProperties().getProperties();
|
||||
return props.containsKey(Constants.WorkspaceProperties.TBS)&&(props.get(Constants.WorkspaceProperties.TBS)!=null);
|
||||
}catch(InternalErrorException e) {
|
||||
throw new WorkspaceInteractionException("Unable to check Synch flag on "+folderId,e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public SyncFolderDescriptor check(boolean recursively) throws WorkspaceInteractionException, InternalException {
|
||||
if(!isSynched()) throw new WorkspaceNotSynchedException("Folder "+folderId+" is not synched.");
|
||||
if(isLocked()&&!isLockOwned())throw new WorkspaceLockedException("Workspace "+folderId+" is locked.");
|
||||
|
||||
SynchFolderConfiguration config=getSynchConfiguration();
|
||||
try{
|
||||
checkFolder(theFolder,recursively,config,null,theFolder.getId(),WorkspaceUtils.safelyGetLastUpdate(theFolder));
|
||||
return new SyncFolderDescriptor(this.folderId,this.theFolder.getPath(),config);
|
||||
}catch(InternalErrorException e) {
|
||||
throw new WorkspaceInteractionException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isLockOwned() throws WorkspaceNotSynchedException, WorkspaceInteractionException, InternalException {
|
||||
String currentProcessId=ProcessIdProvider.instance.get();
|
||||
if(currentProcessId==null) return false;
|
||||
return currentProcessId.equals(getLockId());
|
||||
}
|
||||
|
||||
|
||||
public String getLockId() throws WorkspaceNotSynchedException, WorkspaceInteractionException, InternalException {
|
||||
return getRootThreddsController().readThreddsFile(Constants.LOCK_FILE);
|
||||
}
|
||||
|
||||
public boolean isLocked() throws WorkspaceNotSynchedException, WorkspaceInteractionException, InternalException {
|
||||
return getRootThreddsController().existsThreddsFile(Constants.LOCK_FILE);
|
||||
}
|
||||
|
||||
|
||||
public void configure(SynchFolderConfiguration toSet) throws WorkspaceInteractionException, InternalException {
|
||||
if(isSynched()) throw new WorkspaceInteractionException("Folder "+folderId+" is already configured for synchronization.");
|
||||
log.info("Configuring folder {} as {} ",folderId,toSet);
|
||||
|
||||
|
||||
|
||||
// Checking AND initializing remote folder
|
||||
log.debug("Checking remote folder existence .. ");
|
||||
boolean createCatalog=false;
|
||||
try {
|
||||
String catalogName=toSet.getToCreateCatalogName();
|
||||
|
||||
ThreddsController controller= new ThreddsController(toSet.getRemotePath(),toSet.getTargetToken());
|
||||
if(!controller.existsThreddsFile(null)) {
|
||||
log.info("Folder not found, creating it..");
|
||||
controller.createEmptyFolder(null);
|
||||
createCatalog=true;
|
||||
}else {
|
||||
ThreddsCatalog catalog=controller.getCatalog();
|
||||
if (catalog==null) {
|
||||
createCatalog=true;
|
||||
}else {
|
||||
log.info("Found matching catalog {} ",catalog);
|
||||
catalogName=catalog.getTitle();
|
||||
if(catalogName==null) catalogName=catalog.getDeclaredDataSetScan().iterator().next().getName();
|
||||
toSet.setToCreateCatalogName(catalogName);
|
||||
}
|
||||
}
|
||||
|
||||
if(createCatalog) {
|
||||
log.info("Creating catalog {} ",catalogName);
|
||||
log.debug("Created catalog {}", controller.createCatalog(catalogName));
|
||||
}
|
||||
|
||||
WorkspaceUtils.initProperties(theFolder, toSet.getRemotePath(), toSet.getFilter(),
|
||||
toSet.getTargetToken(),toSet.getToCreateCatalogName(),toSet.getValidateMetadata(),theFolder.getId());
|
||||
|
||||
}catch(InternalException e) {
|
||||
throw new InternalException ("Unable to check/initialize remote folder",e);
|
||||
}catch(InternalErrorException e) {
|
||||
throw new WorkspaceInteractionException("Unable to set Properties to "+folderId,e);
|
||||
}
|
||||
}
|
||||
|
||||
public void dismiss(boolean deleteRemote) throws WorkspaceInteractionException, InternalException {
|
||||
if(!isSynched()) throw new WorkspaceNotSynchedException("Folder "+folderId+" is not synched.");
|
||||
if(isLocked()&&!isLockOwned())throw new WorkspaceLockedException("Workspace "+folderId+" is locked.");
|
||||
|
||||
try {
|
||||
cleanCache();
|
||||
WorkspaceUtils.cleanItem(theFolder);
|
||||
if(deleteRemote)
|
||||
getThreddsController().createEmptyFolder(null);
|
||||
}catch(InternalErrorException e) {
|
||||
throw new WorkspaceInteractionException("Unable to cleanup "+folderId,e);
|
||||
}
|
||||
}
|
||||
|
||||
public void setLastUpdateTime() throws InternalErrorException {
|
||||
WorkspaceUtils.setLastUpdateTime(theFolder, System.currentTimeMillis());
|
||||
}
|
||||
|
||||
|
||||
public void forceUnlock() throws InternalException,WorkspaceInteractionException {
|
||||
try {
|
||||
getRootThreddsController().deleteThreddsFile(Constants.LOCK_FILE);
|
||||
} catch (RemoteFileNotFoundException e) {
|
||||
log.debug("Forced unlock but no file found.",e);
|
||||
} catch (WorkspaceNotSynchedException e) {
|
||||
log.warn("Invoked force lock on not synched folder.",e);
|
||||
} catch (InternalException | WorkspaceInteractionException e) {
|
||||
throw e ;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void lock(String processId) throws WorkspaceNotSynchedException, WorkspaceInteractionException, InternalException {
|
||||
getRootThreddsController().lockFolder(processId);
|
||||
}
|
||||
|
||||
public void unlock() throws WorkspaceNotSynchedException, WorkspaceInteractionException, InternalException {
|
||||
unlock(ProcessIdProvider.instance.get());
|
||||
}
|
||||
|
||||
public void unlock(String processId) throws WorkspaceNotSynchedException, WorkspaceInteractionException, InternalException {
|
||||
String currentLock=getLockId();
|
||||
if(processId.equals(currentLock)) getRootThreddsController().deleteThreddsFile(Constants.LOCK_FILE);
|
||||
else throw new LockNotOwnedException("Process "+processId+" can't remove lock owned by "+currentLock);
|
||||
}
|
||||
|
||||
|
||||
//*************************** PRIVATE
|
||||
|
||||
private void cleanCache() {
|
||||
this.config=null;
|
||||
this.threddsController=null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
private static void checkFolder(WorkspaceFolder folder,boolean recursive, SynchFolderConfiguration rootConfig, String relativePathFromRootFolder, String rootFolderId,Date lastUpdatedRoutine) throws InternalErrorException, InternalException {
|
||||
// Check folder configuration
|
||||
log.trace("Checking folder {} ",folder.getPath());
|
||||
log.debug("Configuration is {}, relativePath is {} ",rootConfig,relativePathFromRootFolder);
|
||||
|
||||
String folderName=folder.getName();
|
||||
|
||||
String currentRemotePath=rootConfig.getRemotePath()+((relativePathFromRootFolder==null)?"":"/"+relativePathFromRootFolder);
|
||||
|
||||
|
||||
|
||||
ThreddsController controller=new ThreddsController(currentRemotePath, rootConfig.getTargetToken());
|
||||
|
||||
|
||||
HashSet<String> currentFolderExistingItem=new HashSet<String>();
|
||||
|
||||
|
||||
log.debug("Initializing properties for {} ",folderName);
|
||||
//INIT PROPERTIES IF NOT PRESENT
|
||||
if(!WorkspaceUtils.isConfigured(folder))
|
||||
WorkspaceUtils.initProperties(folder,currentRemotePath,rootConfig.getFilter(),rootConfig.getTargetToken(),rootConfig.getToCreateCatalogName(),rootConfig.getValidateMetadata(),rootFolderId);
|
||||
|
||||
for(WorkspaceItem item:folder.getChildren()) {
|
||||
String itemName=item.getName();
|
||||
String itemRelativePath=(relativePathFromRootFolder==null)?itemName:relativePathFromRootFolder+"/"+itemName;
|
||||
String itemRemotePath=currentRemotePath+"/"+itemName;
|
||||
if(item.isFolder()) {
|
||||
if(recursive)
|
||||
checkFolder((WorkspaceFolder) item,recursive,rootConfig,itemRelativePath,rootFolderId,lastUpdatedRoutine);
|
||||
else WorkspaceUtils.initProperties(item, itemRemotePath, rootConfig.getFilter(), rootConfig.getTargetToken(),rootConfig.getToCreateCatalogName(),rootConfig.getValidateMetadata(),rootFolderId);
|
||||
}else if(rootConfig.matchesFilter(itemName)) {
|
||||
if(!WorkspaceUtils.isConfigured(item))
|
||||
WorkspaceUtils.initProperties(item, null, null, null,null,null,null);
|
||||
}
|
||||
currentFolderExistingItem.add(itemName);
|
||||
}
|
||||
|
||||
|
||||
// ACTUALLY CHECK STATUS
|
||||
|
||||
if(controller.existsThreddsFile(null)) {
|
||||
SynchronizationStatus folderStatus=SynchronizationStatus.OUTDATED_REMOTE;
|
||||
log.debug("Remote Folder {} exists. Checking status..",currentRemotePath);
|
||||
RemoteFileDescriptor folderDesc=controller.getFileDescriptor();
|
||||
HashSet<String> remoteFolderItems=new HashSet<>(folderDesc.getChildren());
|
||||
|
||||
|
||||
|
||||
|
||||
// CHECK HISTORY
|
||||
Set<String> accountingEntries=WorkspaceUtils.scanAccountingForStatus(folder, rootConfig,
|
||||
currentFolderExistingItem, remoteFolderItems,
|
||||
controller, null, null);
|
||||
if(accountingEntries.isEmpty()) {
|
||||
log.debug("No accounting entries found");
|
||||
folderStatus=SynchronizationStatus.UP_TO_DATE;
|
||||
}
|
||||
|
||||
// CHECK WS ITEMS
|
||||
for(WorkspaceItem item:folder.getChildren())
|
||||
if(item.isFolder()||rootConfig.matchesFilter(item.getName())) {
|
||||
SynchronizationStatus itemStatus=WorkspaceUtils.getStatusAgainstRemote(item, remoteFolderItems, controller,lastUpdatedRoutine);
|
||||
item.getProperties().addProperties(Collections.singletonMap(Constants.WorkspaceProperties.SYNCHRONIZATION_STATUS,itemStatus+""));
|
||||
folderStatus=folderStatus.equals(SynchronizationStatus.UP_TO_DATE)?itemStatus:folderStatus;
|
||||
|
||||
}
|
||||
|
||||
// CHECK REMOTE FOLDER
|
||||
if(folderStatus.equals(SynchronizationStatus.UP_TO_DATE)) {
|
||||
Set<String> toImportItems=WorkspaceUtils.scanRemoteFolder(folderDesc, accountingEntries, currentFolderExistingItem, folder, controller, rootConfig, null, null);
|
||||
if(!toImportItems.isEmpty()) folderStatus=SynchronizationStatus.OUTDATED_WS;
|
||||
}
|
||||
|
||||
folder.getProperties().addProperties(Collections.singletonMap(Constants.WorkspaceProperties.SYNCHRONIZATION_STATUS,folderStatus+""));
|
||||
}else {
|
||||
// Remote Folder not existing, set everything to OUTDATED_REMOTE
|
||||
for(WorkspaceItem item:folder.getChildren())
|
||||
item.getProperties().addProperties(Collections.singletonMap(Constants.WorkspaceProperties.SYNCHRONIZATION_STATUS,SynchronizationStatus.OUTDATED_REMOTE+""));
|
||||
folder.getProperties().addProperties(Collections.singletonMap(Constants.WorkspaceProperties.SYNCHRONIZATION_STATUS,SynchronizationStatus.OUTDATED_REMOTE+""));
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
public File loadCatalogFile() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public void updateCatalogFile(File toUpload) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,356 @@
|
||||
package org.gcube.usecases.ws.thredds.engine.impl;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
|
||||
import org.gcube.common.homelibary.model.items.type.WorkspaceItemType;
|
||||
import org.gcube.common.homelibrary.home.exceptions.InternalErrorException;
|
||||
import org.gcube.common.homelibrary.home.workspace.Properties;
|
||||
import org.gcube.common.homelibrary.home.workspace.WorkspaceFolder;
|
||||
import org.gcube.common.homelibrary.home.workspace.WorkspaceItem;
|
||||
import org.gcube.common.homelibrary.home.workspace.accounting.AccountingEntry;
|
||||
import org.gcube.common.homelibrary.home.workspace.accounting.AccountingEntryRemoval;
|
||||
import org.gcube.common.homelibrary.home.workspace.accounting.AccountingEntryRenaming;
|
||||
import org.gcube.data.transfer.model.RemoteFileDescriptor;
|
||||
import org.gcube.usecases.ws.thredds.Constants;
|
||||
import org.gcube.usecases.ws.thredds.engine.impl.threads.DeleteRemoteRequest;
|
||||
import org.gcube.usecases.ws.thredds.engine.impl.threads.SynchronizationThread;
|
||||
import org.gcube.usecases.ws.thredds.engine.impl.threads.TransferFromThreddsRequest;
|
||||
import org.gcube.usecases.ws.thredds.faults.InternalException;
|
||||
import org.gcube.usecases.ws.thredds.faults.RemoteFileNotFoundException;
|
||||
import org.gcube.usecases.ws.thredds.model.StepReport;
|
||||
import org.gcube.usecases.ws.thredds.model.SynchFolderConfiguration;
|
||||
import org.gcube.usecases.ws.thredds.model.SynchronizedElementInfo.SynchronizationStatus;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Slf4j
|
||||
public class WorkspaceUtils {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Checks current accounting info in order to infere synchronization status.
|
||||
* OwnerProcess and service parameters can be null for check purposes.
|
||||
*
|
||||
* @param folderPath
|
||||
* @param toScanFolder
|
||||
* @param config
|
||||
* @param localChildrenNames
|
||||
* @param remoteChildrenNames
|
||||
* @param folderController
|
||||
*
|
||||
* @param ownerProcess
|
||||
* @param service
|
||||
* @return set of Item names that have been found to be synchronized
|
||||
* @throws InternalErrorException
|
||||
*/
|
||||
static Set<String> scanAccountingForStatus(
|
||||
WorkspaceFolder toScanFolder,
|
||||
SynchFolderConfiguration config,
|
||||
Set<String> localChildrenNames,
|
||||
Set<String> remoteChildrenNames,
|
||||
ThreddsController folderController,
|
||||
|
||||
Process ownerProcess,
|
||||
ExecutorService service) throws InternalErrorException{
|
||||
|
||||
Set<String> handledAccountingEntries=new HashSet<>();
|
||||
|
||||
log.debug("Checking history of {} ",toScanFolder.getPath());
|
||||
|
||||
|
||||
String relativePath=toScanFolder.getProperties().getPropertyValue(Constants.WorkspaceProperties.REMOTE_PATH);
|
||||
|
||||
|
||||
Date folderLastUpdateTime=null;
|
||||
try{
|
||||
folderLastUpdateTime=WorkspaceUtils.safelyGetLastUpdate(toScanFolder);
|
||||
}catch(Throwable t) {
|
||||
log.warn("Unable to get folder {} last update time. Assuming first run.. ",toScanFolder.getName(),t);
|
||||
folderLastUpdateTime=new Date(0l);
|
||||
}
|
||||
// scanning for deletions
|
||||
log.debug("Checking Accounting for {}. Last update time is {} ",toScanFolder.getName(),Constants.DATE_FORMAT.format(folderLastUpdateTime));
|
||||
for(AccountingEntry entry:toScanFolder.getAccounting()) {
|
||||
try {
|
||||
Date eventTime=entry.getDate().getTime();
|
||||
if(folderLastUpdateTime==null|| eventTime.after(folderLastUpdateTime)) { // SKIP IF ENTRY OLDER THAN LAST UPDATE TIME
|
||||
String toDeleteRemote=null;
|
||||
switch(entry.getEntryType()) {
|
||||
case CUT:
|
||||
case REMOVAL:{
|
||||
AccountingEntryRemoval removalEntry=(AccountingEntryRemoval) entry;
|
||||
if(removalEntry.getItemType().equals(WorkspaceItemType.FOLDER)||
|
||||
config.matchesFilter(removalEntry.getItemName()))
|
||||
toDeleteRemote=removalEntry.getItemName();
|
||||
break;
|
||||
}
|
||||
case RENAMING:{
|
||||
AccountingEntryRenaming renamingEntry=(AccountingEntryRenaming) entry;
|
||||
WorkspaceItem newItem=toScanFolder.find(renamingEntry.getNewItemName());
|
||||
if(newItem.isFolder()||config.matchesFilter(renamingEntry.getOldItemName()))
|
||||
toDeleteRemote=renamingEntry.getOldItemName();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if(toDeleteRemote!=null){
|
||||
// SKIP IF LOCAL EXISTS
|
||||
if(localChildrenNames.contains(toDeleteRemote))
|
||||
log.debug("Skipping accounting entry for existing local item {} ",toDeleteRemote);
|
||||
else if(remoteChildrenNames.contains(toDeleteRemote)) {
|
||||
log.debug("Checking age of remote {} ",toDeleteRemote);
|
||||
|
||||
// IF REMOTE OLDER THAN ENTRY -> DELETE REQUEST
|
||||
// IF REMOTE NEWER -> IMPORT REQUEST
|
||||
RemoteFileDescriptor remote=folderController.getFileDescriptor(relativePath+"/"+toDeleteRemote);
|
||||
Date remoteDate=new Date(remote.getLastUpdate());
|
||||
log.debug("Last remote update : {} . Event date {} ",Constants.DATE_FORMAT.format(remoteDate),Constants.DATE_FORMAT.format(eventTime));
|
||||
if(service!=null) {
|
||||
log.debug("Service is not null. Submitting request ... ");
|
||||
if(eventTime.after(remoteDate)) {
|
||||
service.execute(new SynchronizationThread(new DeleteRemoteRequest(ownerProcess, toScanFolder,toDeleteRemote)));
|
||||
handledAccountingEntries.add(toDeleteRemote);
|
||||
log.debug("Submitted DELETION request number {} ",ownerProcess.getStatus().getQueuedTransfers().incrementAndGet());
|
||||
}
|
||||
// }else {
|
||||
// service.execute(new SynchronizationThread(new TransferFromThreddsRequest(ownerProcess, null, toScanFolder, toDeleteRemote)));
|
||||
// log.debug("Submitted UPDATE-LOCAL request number {} ",ownerProcess.getStatus().getQueuedTransfers().incrementAndGet());
|
||||
// }
|
||||
}
|
||||
}else log.debug("To delete remote {} not found. skipping it.. ",toDeleteRemote);
|
||||
// SKIP IF REMOTE NOT FOUND
|
||||
}
|
||||
}
|
||||
}catch(Throwable t) {
|
||||
log.error("Unable to submit deletion request for {} ",entry,t);
|
||||
}
|
||||
}
|
||||
|
||||
return handledAccountingEntries;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Scans remote Folder in order to gather elements to be synchronized.
|
||||
* OwnerProcess and Service can be null for check purposes.
|
||||
*
|
||||
*
|
||||
* @param folderPath
|
||||
* @param folderDesc
|
||||
* @param handledAccountingEntries
|
||||
* @param handledWorkspaceItemEntries
|
||||
* @param toScanFolder
|
||||
* @param folderController
|
||||
* @param config
|
||||
* @param ownerProcess
|
||||
* @param service
|
||||
* @return
|
||||
* @throws InternalException
|
||||
* @throws InternalErrorException
|
||||
*/
|
||||
static Set<String> scanRemoteFolder(
|
||||
RemoteFileDescriptor folderDesc,
|
||||
Set<String> handledAccountingEntries,
|
||||
Set<String> handledWorkspaceItemEntries,
|
||||
WorkspaceFolder toScanFolder,
|
||||
ThreddsController folderController,
|
||||
SynchFolderConfiguration config,
|
||||
Process ownerProcess,
|
||||
ExecutorService service) throws InternalException, InternalErrorException{
|
||||
|
||||
log.debug("Checking remote content for {}. Remote Absolute Path is {} ",toScanFolder.getPath(),folderDesc.getAbsolutePath());
|
||||
Set<String> handledRemoteElements=new HashSet<String>();
|
||||
|
||||
// String relativePath=toScanFolder.getProperties().getPropertyValue(Constants.WorkspaceProperties.REMOTE_PATH);
|
||||
|
||||
|
||||
if(!folderDesc.isDirectory()) throw new InternalException("Remote Descriptor "+folderDesc.getAbsolutePath()+" Is not a directory. ");
|
||||
for(String child:folderDesc.getChildren()) {
|
||||
// skip if already handled with accounting
|
||||
if(handledAccountingEntries.contains(child))
|
||||
log.debug("Skipping remote child {} because already handled with accouting", child);
|
||||
// skip if already handled with local items
|
||||
else if(handledWorkspaceItemEntries.contains(child))
|
||||
log.debug("Skipping remote child {} because already handled with respective item",child);
|
||||
else {
|
||||
RemoteFileDescriptor childDesc=folderController.getFileDescriptor(child);
|
||||
if(childDesc.isDirectory()) {
|
||||
handledRemoteElements.add(child);
|
||||
}else if (config.matchesFilter(child)){
|
||||
log.debug("Child {} matches filter...");
|
||||
handledRemoteElements.add(child);
|
||||
if(service!=null) {
|
||||
service.execute(new SynchronizationThread(new TransferFromThreddsRequest(ownerProcess, null, toScanFolder, child)));
|
||||
log.debug("Submitted IMPORT request number {} ",ownerProcess.getStatus().getQueuedTransfers().incrementAndGet());
|
||||
}
|
||||
// import if matching
|
||||
}else log.debug("Skipping not matching remote {} ",child);
|
||||
// skip if doesn't match filter or isn't folder
|
||||
}
|
||||
}
|
||||
return handledRemoteElements;
|
||||
}
|
||||
|
||||
|
||||
static void initProperties(WorkspaceItem toInit, String remotePath, String filter, String targetToken,
|
||||
String catalogName,Boolean validateMeta, String rootFolderId) throws InternalErrorException {
|
||||
|
||||
Map<String,String> toSetProperties=toInit.getProperties().getProperties();
|
||||
initIfMissing(toSetProperties,Constants.WorkspaceProperties.TBS,"true");
|
||||
|
||||
|
||||
initIfMissing(toSetProperties,Constants.WorkspaceProperties.LAST_UPDATE_TIME,0l+"");
|
||||
initIfMissing(toSetProperties,Constants.WorkspaceProperties.LAST_UPDATE_STATUS,StepReport.Status.OK+"");
|
||||
initIfMissing(toSetProperties,Constants.WorkspaceProperties.SYNCHRONIZATION_STATUS,SynchronizationStatus.UP_TO_DATE+"");
|
||||
|
||||
if(toInit.isFolder()) {
|
||||
initIfMissing(toSetProperties,Constants.WorkspaceProperties.SYNCH_FILTER,filter);
|
||||
initIfMissing(toSetProperties,Constants.WorkspaceProperties.REMOTE_PATH,remotePath);
|
||||
initIfMissing(toSetProperties,Constants.WorkspaceProperties.REMOTE_PERSISTENCE,Constants.THREDDS_PERSISTENCE);
|
||||
initIfMissing(toSetProperties,Constants.WorkspaceProperties.TARGET_TOKEN,targetToken);
|
||||
initIfMissing(toSetProperties,Constants.WorkspaceProperties.RELATED_CATALOG,catalogName);
|
||||
initIfMissing(toSetProperties,Constants.WorkspaceProperties.VALIDATE_METADATA,validateMeta+"");
|
||||
initIfMissing(toSetProperties,Constants.WorkspaceProperties.ROOT_FOLDER_ID,rootFolderId);
|
||||
}else {
|
||||
initIfMissing(toSetProperties,Constants.WorkspaceProperties.METADATA_UUID,null);
|
||||
}
|
||||
toInit.getProperties().addProperties(toSetProperties);
|
||||
}
|
||||
|
||||
|
||||
private static void initIfMissing(Map<String,String> current,String key,String defaultValue) {
|
||||
if(!current.containsKey(key)||
|
||||
current.get(key)==null||
|
||||
current.get(key).equals("null")) current.put(key, defaultValue);
|
||||
}
|
||||
|
||||
|
||||
static boolean isConfigured(WorkspaceItem toCheck) throws InternalErrorException {
|
||||
return isConfigured(toCheck.getProperties().getProperties());
|
||||
}
|
||||
static boolean isConfigured(Map<String,String> toCheckProperties) {
|
||||
return (toCheckProperties.containsKey(Constants.WorkspaceProperties.TBS)&&toCheckProperties.get(Constants.WorkspaceProperties.TBS)!=null);
|
||||
}
|
||||
|
||||
static SynchronizationStatus getStatusAgainstRemote(WorkspaceItem item, Set<String> existingRemote, ThreddsController remoteFolderController,Date lastUpdateRoutine) throws NumberFormatException, InternalErrorException, RemoteFileNotFoundException {
|
||||
String itemName=item.getName();
|
||||
SynchronizationStatus status=SynchronizationStatus.OUTDATED_REMOTE;
|
||||
if(existingRemote.contains(itemName)) {
|
||||
RemoteFileDescriptor desc=remoteFolderController.getFileDescriptor(itemName);
|
||||
Date remoteDate=new Date(desc.getLastUpdate());
|
||||
Date localDate=item.getLastModificationTime().getTime();
|
||||
Date lastUpdate=safelyGetLastUpdate(item);
|
||||
|
||||
if(localDate.equals(lastUpdate)) {
|
||||
//LAST MODIFCATION WAS FROM SYNCHRONIZATION
|
||||
if(remoteDate.after(lastUpdate)) status=SynchronizationStatus.OUTDATED_WS;
|
||||
else status=SynchronizationStatus.UP_TO_DATE;
|
||||
}else
|
||||
if(remoteDate.before(localDate)) { // REMOTE OLDER THAN LOCAL
|
||||
if(isModifiedAfter(item,lastUpdateRoutine)) status=SynchronizationStatus.OUTDATED_REMOTE; // IT's been locally modified from last routine
|
||||
else status=SynchronizationStatus.UP_TO_DATE;
|
||||
}
|
||||
else if(remoteDate.after(localDate)) { // REMOTE NEWER &..
|
||||
if (remoteDate.equals(lastUpdate))status =SynchronizationStatus.UP_TO_DATE; // REMOTE DATE == LAST UPDATE ROUTINE -> UP TO DATE
|
||||
else if (remoteDate.before(lastUpdate))status =SynchronizationStatus.OUTDATED_REMOTE; // REMOTE DATE < LAST UPDATE -> transfer to thredds, last update was faulty
|
||||
else status=SynchronizationStatus.OUTDATED_WS; // REMOTE DATE != LAST UPDATE -> import from thredds
|
||||
}
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// /**
|
||||
// *
|
||||
// * @return max date between creation time, last modification time && LAST-UPDATE-PROP
|
||||
// * @throws InternalErrorException
|
||||
// * @throws NumberFormatException
|
||||
// */
|
||||
// static Date getMaxLastUpdate(WorkspaceItem item) throws NumberFormatException, InternalErrorException {
|
||||
// return new Date(Long.max(Long.parseLong(item.getProperties().getPropertyValue(Constants.WorkspaceProperties.LAST_UPDATE_TIME)),item.getLastModificationTime().getTimeInMillis()));
|
||||
// }
|
||||
|
||||
static Date safelyGetLastUpdate(WorkspaceItem item) throws InternalErrorException {
|
||||
try {
|
||||
return new Date(Long.parseLong(item.getProperties().getPropertyValue(Constants.WorkspaceProperties.LAST_UPDATE_TIME)));
|
||||
}catch(NumberFormatException e) {
|
||||
log.debug("Unable to get last update time for {} ",item.getName(),e);
|
||||
return new Date(0l);
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isModifiedAfter(WorkspaceItem item,Date fromDate) throws InternalErrorException {
|
||||
for(AccountingEntry entry:item.getAccounting()) {
|
||||
if(entry.getDate().getTime().after(fromDate)) {
|
||||
switch(entry.getEntryType()) {
|
||||
case PASTE:
|
||||
case CREATE:
|
||||
case RESTORE:
|
||||
case UPDATE:
|
||||
case ADD: return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
static void cleanItem(WorkspaceItem item) throws InternalErrorException {
|
||||
Properties props=item.getProperties();
|
||||
if(props.hasProperty(Constants.WorkspaceProperties.TBS)) {
|
||||
if(item.isFolder()) {
|
||||
props.addProperties(Constants.cleanedFolderPropertiesMap);
|
||||
for(WorkspaceItem child : ((WorkspaceFolder)item).getChildren())
|
||||
cleanItem(child);
|
||||
}else props.addProperties(Constants.cleanedItemPropertiesMap);
|
||||
}
|
||||
}
|
||||
|
||||
static void setLastUpdateTime(WorkspaceFolder folder,long toSetTime) throws InternalErrorException {
|
||||
StepReport.Status currentWSStatus=StepReport.Status.valueOf(folder.getProperties().getPropertyValue(Constants.WorkspaceProperties.LAST_UPDATE_STATUS));
|
||||
|
||||
if(currentWSStatus.equals(StepReport.Status.OK))
|
||||
folder.getProperties().addProperties(Collections.singletonMap(Constants.WorkspaceProperties.LAST_UPDATE_TIME, toSetTime+""));
|
||||
|
||||
for(WorkspaceItem item:folder.getChildren())
|
||||
if(item.isFolder()) setLastUpdateTime((WorkspaceFolder) item, toSetTime);
|
||||
|
||||
}
|
||||
|
||||
public static SynchFolderConfiguration loadConfiguration(WorkspaceItem item) throws InternalErrorException {
|
||||
if(item.isFolder()) {
|
||||
Properties props=item.getProperties();
|
||||
SynchFolderConfiguration config=new SynchFolderConfiguration();
|
||||
config.setFilter(props.getPropertyValue(Constants.WorkspaceProperties.SYNCH_FILTER));
|
||||
config.setRemotePath(props.getPropertyValue(Constants.WorkspaceProperties.REMOTE_PATH));
|
||||
config.setRemotePersistence(props.getPropertyValue(Constants.WorkspaceProperties.REMOTE_PERSISTENCE));
|
||||
config.setTargetToken(props.getPropertyValue(Constants.WorkspaceProperties.TARGET_TOKEN));
|
||||
config.setToCreateCatalogName(props.getPropertyValue(Constants.WorkspaceProperties.RELATED_CATALOG));
|
||||
config.setValidateMetadata(Boolean.parseBoolean(props.getPropertyValue(Constants.WorkspaceProperties.VALIDATE_METADATA)));
|
||||
config.setRootFolderId(props.getPropertyValue(Constants.WorkspaceProperties.ROOT_FOLDER_ID));
|
||||
return config;
|
||||
}else return loadConfiguration(item.getParent());
|
||||
}
|
||||
|
||||
static void resetStatus(WorkspaceItem item) throws InternalErrorException {
|
||||
if(item.isFolder()) {
|
||||
for(WorkspaceItem child: ((WorkspaceFolder)item).getChildren())
|
||||
resetStatus(child);
|
||||
}
|
||||
Map<String,String> props=item.getProperties().getProperties();
|
||||
if(props.containsKey(Constants.WorkspaceProperties.LAST_UPDATE_STATUS)) {
|
||||
props.put(Constants.WorkspaceProperties.LAST_UPDATE_STATUS, StepReport.Status.OK+"");
|
||||
item.getProperties().addProperties(props);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
package org.gcube.usecases.ws.thredds.engine.impl.threads;
|
||||
|
||||
import org.gcube.common.homelibrary.home.workspace.WorkspaceFolder;
|
||||
import org.gcube.usecases.ws.thredds.engine.impl.Process;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class DeleteRemoteRequest extends SynchronizationRequest {
|
||||
|
||||
private String toRemoveName;
|
||||
|
||||
public DeleteRemoteRequest(Process process,WorkspaceFolder location,String name) {
|
||||
super(process,location);
|
||||
this.toRemoveName=name;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
package org.gcube.usecases.ws.thredds.engine.impl.threads;
|
||||
|
||||
public class ProcessIdProvider {
|
||||
|
||||
public static ProcessIdProvider instance=new ProcessIdProvider();
|
||||
|
||||
private static final InheritableThreadLocal<String> threadProcessId=
|
||||
new InheritableThreadLocal<String>() {
|
||||
@Override
|
||||
protected String initialValue() {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
private ProcessIdProvider() {
|
||||
|
||||
}
|
||||
|
||||
public String get() {
|
||||
return threadProcessId.get();
|
||||
}
|
||||
|
||||
public void set(String processId) {
|
||||
threadProcessId.set(processId);
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
threadProcessId.remove();
|
||||
}
|
||||
}
|
@ -0,0 +1,59 @@
|
||||
package org.gcube.usecases.ws.thredds.engine.impl.threads;
|
||||
|
||||
import java.util.concurrent.ExecutorService;
|
||||
|
||||
import org.gcube.common.homelibrary.home.exceptions.InternalErrorException;
|
||||
import org.gcube.usecases.ws.thredds.engine.impl.Process;
|
||||
import org.gcube.usecases.ws.thredds.engine.impl.ProcessDescriptor;
|
||||
import org.gcube.usecases.ws.thredds.engine.impl.WorkspaceFolderManager;
|
||||
import org.gcube.usecases.ws.thredds.faults.InternalException;
|
||||
import org.gcube.usecases.ws.thredds.faults.WorkspaceInteractionException;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.NonNull;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Data
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class ProcessInitializationThread implements Runnable {
|
||||
|
||||
@NonNull
|
||||
private Process theProcess;
|
||||
@NonNull
|
||||
private ExecutorService service;
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
ProcessDescriptor descriptor=theProcess.getDescriptor();
|
||||
ProcessIdProvider.instance.set(descriptor.getProcessId());
|
||||
log.info("Initialization of process {} ",descriptor);
|
||||
theProcess.getStatus().setCurrentMessage("Gathering synchronization information...");
|
||||
try {
|
||||
|
||||
WorkspaceFolderManager manager=new WorkspaceFolderManager(descriptor.getFolderId());
|
||||
|
||||
log.debug("Updateing synchronization status..");
|
||||
manager.check(true);
|
||||
log.debug("Launching requests...");
|
||||
theProcess.launch(service);
|
||||
|
||||
}catch(WorkspaceInteractionException e) {
|
||||
log.error("Unable to proceed..",e);
|
||||
theProcess.cancel();
|
||||
} catch (InternalException e) {
|
||||
log.error("Unable to proceed..",e);
|
||||
theProcess.cancel();
|
||||
} catch (InternalErrorException e) {
|
||||
log.error("Unable to proceed..",e);
|
||||
theProcess.cancel();
|
||||
}catch(Throwable t) {
|
||||
log.error("Unexpected Error : ",t);
|
||||
theProcess.cancel();
|
||||
}finally {
|
||||
ProcessIdProvider.instance.reset();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,113 @@
|
||||
package org.gcube.usecases.ws.thredds.engine.impl.threads;
|
||||
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.FileWriter;
|
||||
|
||||
import org.gcube.common.homelibrary.home.exceptions.InternalErrorException;
|
||||
import org.gcube.common.homelibrary.home.workspace.WorkspaceItem;
|
||||
import org.gcube.usecases.ws.thredds.Constants;
|
||||
import org.gcube.usecases.ws.thredds.SyncEngine;
|
||||
|
||||
import lombok.Synchronized;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Slf4j
|
||||
public class RequestLogger {
|
||||
|
||||
|
||||
private static RequestLogger instance=null;
|
||||
|
||||
@Synchronized
|
||||
public static RequestLogger get() {
|
||||
if(instance==null) {
|
||||
instance=new RequestLogger();
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
|
||||
|
||||
BufferedWriter writer = null;
|
||||
|
||||
private RequestLogger() {
|
||||
SyncEngine engine=SyncEngine.get();
|
||||
if(engine.isRequestLoggerEnabled()) {
|
||||
String path=engine.getRequestLoggerPath();
|
||||
log.info("Initializing Request Logger to path {} ",path);
|
||||
try{
|
||||
writer = new BufferedWriter(new FileWriter(path, false));
|
||||
}catch(Throwable t) {
|
||||
log.warn("Unable to initialize Writer on path {} ",path,t);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void log(SynchronizationRequest request) {
|
||||
if(writer!=null) {
|
||||
String logString="INVALID";
|
||||
if(request instanceof DeleteRemoteRequest) {
|
||||
DeleteRemoteRequest deleteRequest=(DeleteRemoteRequest) request;
|
||||
logString=String.format("DELETE %s from %s (WS-Path: %s)", deleteRequest.getToRemoveName(),getRemotePath(deleteRequest.getLocation()),getWSPath(deleteRequest.getLocation()));
|
||||
}else if(request instanceof TransferToThreddsRequest) {
|
||||
TransferToThreddsRequest transferRequest=(TransferToThreddsRequest) request;
|
||||
logString=String.format("EXPORT %s to %s from %s", getName(transferRequest.getToTransfer()),getRemotePath(transferRequest.getToTransfer()),getWSPath(transferRequest.getToTransfer()));
|
||||
}else if(request instanceof TransferFromThreddsRequest) {
|
||||
TransferFromThreddsRequest transferRequest=(TransferFromThreddsRequest)request;
|
||||
if(transferRequest.getTargetItem()!=null)
|
||||
logString=String.format("UPDATE LOCAL %s in %s from %s ", getName(transferRequest.getTargetItem()),getWSPath(transferRequest.getLocation()),getRemotePath(transferRequest.getLocation()));
|
||||
else
|
||||
logString=String.format("IMPORT LOCAL %s in %s from %s ", transferRequest.getRemoteFilename(),getWSPath(transferRequest.getLocation()),getRemotePath(transferRequest.getLocation()));
|
||||
}
|
||||
try {
|
||||
writer.write(logString+"\n");
|
||||
}catch(Throwable t) {
|
||||
log.warn("Exception wile trying to write log",t);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void close() {
|
||||
if(writer!=null) {
|
||||
try {
|
||||
writer.flush();
|
||||
writer.close();
|
||||
}catch(Throwable t) {
|
||||
log.warn("Unable to close writer ",t);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static final String getRemotePath(WorkspaceItem item) {
|
||||
try{
|
||||
if(item.isFolder()) return item.getProperties().getPropertyValue(Constants.WorkspaceProperties.REMOTE_PATH);
|
||||
else return getRemotePath(item.getParent());
|
||||
}catch(InternalErrorException e) {
|
||||
log.warn("Unable to get Remote Path ",e);
|
||||
return "N/A";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static final String getName(WorkspaceItem item) {
|
||||
try {
|
||||
return item.getName();
|
||||
}catch(InternalErrorException e) {
|
||||
log.warn("Unable to get name ",e);
|
||||
return "N/A";
|
||||
}
|
||||
}
|
||||
|
||||
private static final String getWSPath(WorkspaceItem item) {
|
||||
try{
|
||||
if(item.isFolder()) return item.getPath();
|
||||
else return getRemotePath(item.getParent());
|
||||
}catch(InternalErrorException e) {
|
||||
log.warn("Unable to get WS Path ",e);
|
||||
return "N/A";
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
package org.gcube.usecases.ws.thredds.engine.impl.threads;
|
||||
|
||||
import org.gcube.common.homelibrary.home.workspace.WorkspaceFolder;
|
||||
import org.gcube.usecases.ws.thredds.engine.impl.Process;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.NonNull;
|
||||
|
||||
@Data
|
||||
public abstract class SynchronizationRequest {
|
||||
|
||||
@NonNull
|
||||
private Process process;
|
||||
@NonNull
|
||||
private WorkspaceFolder location;
|
||||
}
|
@ -0,0 +1,289 @@
|
||||
package org.gcube.usecases.ws.thredds.engine.impl.threads;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.InputStream;
|
||||
import java.nio.file.Files;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.gcube.common.homelibrary.home.exceptions.InternalErrorException;
|
||||
import org.gcube.common.homelibrary.home.workspace.WorkspaceFolder;
|
||||
import org.gcube.common.homelibrary.home.workspace.WorkspaceItem;
|
||||
import org.gcube.data.transfer.library.TransferResult;
|
||||
import org.gcube.data.transfer.model.Destination;
|
||||
import org.gcube.data.transfer.model.DestinationClashPolicy;
|
||||
import org.gcube.data.transfer.model.ExecutionReport;
|
||||
import org.gcube.data.transfer.model.ExecutionReport.ExecutionReportFlag;
|
||||
import org.gcube.data.transfer.model.PluginInvocation;
|
||||
import org.gcube.data.transfer.model.RemoteFileDescriptor;
|
||||
import org.gcube.data.transfer.model.plugins.thredds.DataSet;
|
||||
import org.gcube.data.transfer.model.plugins.thredds.ThreddsInfo;
|
||||
import org.gcube.spatial.data.sdi.interfaces.Metadata;
|
||||
import org.gcube.spatial.data.sdi.model.metadata.MetadataPublishOptions;
|
||||
import org.gcube.spatial.data.sdi.model.metadata.MetadataReport;
|
||||
import org.gcube.spatial.data.sdi.model.metadata.TemplateInvocationBuilder;
|
||||
import org.gcube.spatial.data.sdi.plugins.SDIAbstractPlugin;
|
||||
import org.gcube.usecases.ws.thredds.Constants;
|
||||
import org.gcube.usecases.ws.thredds.NetUtils;
|
||||
import org.gcube.usecases.ws.thredds.engine.impl.ProcessStatus;
|
||||
import org.gcube.usecases.ws.thredds.engine.impl.ThreddsController;
|
||||
import org.gcube.usecases.ws.thredds.engine.impl.WorkspaceUtils;
|
||||
import org.gcube.usecases.ws.thredds.faults.CancellationException;
|
||||
import org.gcube.usecases.ws.thredds.faults.DataTransferPluginError;
|
||||
import org.gcube.usecases.ws.thredds.faults.InternalException;
|
||||
import org.gcube.usecases.ws.thredds.faults.RemoteFileNotFoundException;
|
||||
import org.gcube.usecases.ws.thredds.model.StepReport;
|
||||
import org.gcube.usecases.ws.thredds.model.StepReport.OperationType;
|
||||
import org.gcube.usecases.ws.thredds.model.StepReport.Status;
|
||||
import org.gcube.usecases.ws.thredds.model.SynchFolderConfiguration;
|
||||
import org.gcube.usecases.ws.thredds.model.SynchronizedElementInfo.SynchronizationStatus;
|
||||
|
||||
import lombok.Synchronized;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Slf4j
|
||||
public class SynchronizationThread implements Runnable {
|
||||
|
||||
private SynchronizationRequest theRequest;
|
||||
|
||||
public SynchronizationThread(SynchronizationRequest theRequest) {
|
||||
super();
|
||||
this.theRequest = theRequest;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
ProcessIdProvider.instance.set(theRequest.getProcess().getDescriptor().getProcessId());
|
||||
log.debug("Executing Transfer request {} ",theRequest);
|
||||
RequestLogger.get().log(theRequest);
|
||||
String reportMessage="Never started";
|
||||
String reportItemName="Still Unknown";
|
||||
Status toSetStatus=Status.ERROR;
|
||||
WorkspaceFolder parentFolder=theRequest.getLocation();
|
||||
try {
|
||||
checkCancelledProcess();
|
||||
SynchFolderConfiguration synchConfig=WorkspaceUtils.loadConfiguration(theRequest.getLocation());
|
||||
ThreddsController controller=new ThreddsController(synchConfig.getRemotePath(), synchConfig.getTargetToken());
|
||||
|
||||
if(theRequest instanceof TransferToThreddsRequest) {
|
||||
TransferToThreddsRequest request=(TransferToThreddsRequest) theRequest;
|
||||
WorkspaceItem item=request.getToTransfer();
|
||||
|
||||
//look for metadata in same folder
|
||||
String itemName=item.getName();
|
||||
reportItemName=itemName;
|
||||
String toLookMetadataName=itemName.substring(0, itemName.lastIndexOf("."))+".xml";
|
||||
WorkspaceItem metadataItem=getFileByName(item.getParent(),false,toLookMetadataName);
|
||||
|
||||
// if not present, generate with sis/geotk
|
||||
Destination toSetDestination=new Destination();
|
||||
toSetDestination.setCreateSubfolders(true);
|
||||
toSetDestination.setDestinationFileName(itemName);
|
||||
toSetDestination.setOnExistingFileName(DestinationClashPolicy.REWRITE);
|
||||
toSetDestination.setOnExistingSubFolder(DestinationClashPolicy.APPEND);
|
||||
toSetDestination.setPersistenceId(synchConfig.getRemotePersistence());
|
||||
|
||||
//NB ITEM IS SUPPOSED TO HAVE REMOTE PATH
|
||||
String fileLocation=request.getLocation().getProperties().getPropertyValue(Constants.WorkspaceProperties.REMOTE_PATH);
|
||||
toSetDestination.setSubFolder(fileLocation);
|
||||
|
||||
|
||||
checkCancelledProcess();
|
||||
|
||||
|
||||
Set<PluginInvocation> invocations=null;
|
||||
if(metadataItem==null) {
|
||||
log.debug("Metadata not found, asking SIS/GEOTK for generation..");
|
||||
invocations=Collections.singleton(new PluginInvocation(Constants.SIS_PLUGIN_ID));
|
||||
}
|
||||
log.info("Transferring to {} with invocations {} ",toSetDestination,invocations);
|
||||
|
||||
ThreddsInfo info=controller.getThreddsInfo();
|
||||
|
||||
DataSet dataset=info.getDataSetFromLocation(info.getLocalBasePath()+"/"+fileLocation);
|
||||
|
||||
// ThreddsCatalog catalog=controller.getCatalog();
|
||||
|
||||
checkCancelledProcess();
|
||||
|
||||
TransferResult result=controller.transferFile(toSetDestination, item.getPublicLink(false), invocations);
|
||||
|
||||
|
||||
Map<String,String> toSetProperties=new HashMap<String,String>();
|
||||
|
||||
|
||||
String toSetMetadataUUID=null;
|
||||
|
||||
Boolean validateMetadata=synchConfig.getValidateMetadata();
|
||||
|
||||
|
||||
checkCancelledProcess();
|
||||
if(metadataItem==null) {
|
||||
ExecutionReport report=result.getExecutionReports().get(Constants.SIS_PLUGIN_ID);
|
||||
if(!report.getFlag().equals(ExecutionReportFlag.SUCCESS)) throw new DataTransferPluginError("Unable to Extract Metadata for "+itemName+" Message is "+report.getMessage());
|
||||
else toSetMetadataUUID=report.getMessage();
|
||||
|
||||
}else {
|
||||
MetadataReport metaReport=publishMetadata(metadataItem,info.getHostname(),itemName,dataset.getPath(),validateMetadata);
|
||||
toSetMetadataUUID=metaReport.getPublishedUUID();
|
||||
}
|
||||
|
||||
toSetProperties.put(Constants.WorkspaceProperties.LAST_UPDATE_TIME, controller.getFileDescriptor(itemName).getLastUpdate()+"");
|
||||
toSetProperties.put(Constants.WorkspaceProperties.METADATA_UUID, toSetMetadataUUID);
|
||||
|
||||
toSetProperties.put(Constants.WorkspaceProperties.SYNCHRONIZATION_STATUS, SynchronizationStatus.UP_TO_DATE+"");
|
||||
item.getProperties().addProperties(toSetProperties);
|
||||
|
||||
reportMessage="Successfully transferred and published.";
|
||||
// End ws->th
|
||||
} else if(theRequest instanceof TransferFromThreddsRequest) {
|
||||
Map<String,String> toSetProperties=new HashMap<String,String>();
|
||||
TransferFromThreddsRequest importRequest=(TransferFromThreddsRequest) theRequest;
|
||||
String toImportName=null;
|
||||
WorkspaceItem targetItem=null;
|
||||
if(importRequest.getTargetItem()==null) {
|
||||
//Target Item will be created
|
||||
toImportName=importRequest.getRemoteFilename();
|
||||
reportMessage="Importing remote file..";
|
||||
}else {
|
||||
//Target Item already exists
|
||||
toImportName=importRequest.getTargetItem().getName();
|
||||
targetItem=importRequest.getTargetItem();
|
||||
reportMessage="Updating file..";
|
||||
}
|
||||
|
||||
reportItemName=toImportName;
|
||||
|
||||
RemoteFileDescriptor toImport=controller.getFileDescriptor(toImportName);
|
||||
|
||||
toSetProperties.put(Constants.WorkspaceProperties.LAST_UPDATE_TIME, toImport.getLastUpdate()+"");
|
||||
InputStream source=null;
|
||||
try {
|
||||
source=controller.getInputStream(toImportName);
|
||||
if(targetItem==null)
|
||||
targetItem=parentFolder.createExternalFileItem(toImportName, "Imported from Thredds", null, source);
|
||||
else
|
||||
targetItem.updateItem(source);
|
||||
targetItem.getProperties().addProperties(toSetProperties);
|
||||
}finally {
|
||||
if(source!=null)
|
||||
source.close();
|
||||
}
|
||||
reportMessage="File successfully imported";
|
||||
|
||||
}else if(theRequest instanceof DeleteRemoteRequest) {
|
||||
DeleteRemoteRequest deleteRequest=(DeleteRemoteRequest) theRequest;
|
||||
reportItemName=deleteRequest.getToRemoveName();
|
||||
|
||||
log.debug("Going to delete {} from ",reportItemName,synchConfig.getRemotePath());
|
||||
|
||||
RemoteFileDescriptor desc=controller.getFileDescriptor(reportItemName);
|
||||
if(desc.isDirectory()) {
|
||||
log.debug("Remote {} is directory.. Cleaning it up, first.",reportItemName);
|
||||
controller.createEmptyFolder(null);
|
||||
}
|
||||
controller.deleteThreddsFile(reportItemName);
|
||||
reportMessage="Successfully removed";
|
||||
}
|
||||
log.info("Synchronization of {} successful.",reportItemName);
|
||||
toSetStatus=Status.OK;
|
||||
}catch(CancellationException e) {
|
||||
log.debug("Process cancelled.. ",e);
|
||||
reportMessage="CancelledProcess";
|
||||
toSetStatus=Status.CANCELLED;
|
||||
}catch(DataTransferPluginError e) {
|
||||
log.debug("Unable to extract metadata ",e);
|
||||
reportMessage="Unable to extract metadata : "+e.getMessage();
|
||||
toSetStatus=Status.ERROR;
|
||||
}catch(RemoteFileNotFoundException e) {
|
||||
log.debug("Remote File not found ",e);
|
||||
reportMessage="Remote File not found : "+e.getMessage();
|
||||
toSetStatus=Status.ERROR;
|
||||
}catch(InternalErrorException e) {
|
||||
log.debug("Internal generic exception ",e);
|
||||
reportMessage="Internal error : "+e.getMessage();
|
||||
toSetStatus=Status.ERROR;
|
||||
}catch(Throwable t) {
|
||||
log.debug("Internal generic exception ",t);
|
||||
reportMessage="Unexpected exception : "+t.getMessage();
|
||||
toSetStatus=Status.ERROR;
|
||||
}finally {
|
||||
updateParentProperty(parentFolder, toSetStatus);
|
||||
submitReport(reportItemName,reportMessage,toSetStatus);
|
||||
ProcessIdProvider.instance.reset();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Synchronized
|
||||
private static void updateParentProperty(WorkspaceFolder folder,StepReport.Status toSetStatus) {
|
||||
try {
|
||||
String currentValue=folder.getProperties().getProperties().get(Constants.WorkspaceProperties.LAST_UPDATE_STATUS);
|
||||
if(currentValue==null||currentValue.isEmpty()||currentValue.equals("null"))
|
||||
folder.getProperties().addProperties(Collections.singletonMap(Constants.WorkspaceProperties.LAST_UPDATE_STATUS, toSetStatus+""));
|
||||
else {
|
||||
StepReport.Status currentWSStatus=StepReport.Status.valueOf(currentValue);
|
||||
if(currentWSStatus.equals(StepReport.Status.OK)&&!toSetStatus.equals(currentWSStatus))
|
||||
folder.getProperties().addProperties(Collections.singletonMap(Constants.WorkspaceProperties.LAST_UPDATE_STATUS, toSetStatus+""));
|
||||
}
|
||||
}catch(Throwable t) {
|
||||
log.warn("Unable to update folder status ",t);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void checkCancelledProcess() throws CancellationException{
|
||||
if(theRequest.getProcess().getStatus().
|
||||
getStatus().equals(ProcessStatus.Status.STOPPED))
|
||||
throw new CancellationException("Process "+theRequest.getProcess().getDescriptor().getProcessId()+" has been cancelled");
|
||||
}
|
||||
|
||||
|
||||
private void submitReport(String elementName,String message,StepReport.Status status) {
|
||||
StepReport report=new StepReport(elementName,message,status,OperationType.WS_TO_TH,System.currentTimeMillis());
|
||||
|
||||
if(theRequest instanceof TransferToThreddsRequest) report.setOperationType(OperationType.WS_TO_TH);
|
||||
else if(theRequest instanceof TransferFromThreddsRequest) report.setOperationType(OperationType.TH_TO_WS);
|
||||
else if(theRequest instanceof DeleteRemoteRequest) report.setOperationType(OperationType.DELETE_REMOTE);
|
||||
else throw new RuntimeException("Unknown operation request "+theRequest);
|
||||
theRequest.getProcess().onStep(report);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
private static MetadataReport publishMetadata(WorkspaceItem toPublish, String threddsHostname,String filename,String publicPath,Boolean validate) throws Exception{
|
||||
File tempMetaFile=null;
|
||||
try {
|
||||
Metadata meta=SDIAbstractPlugin.metadata().build();
|
||||
tempMetaFile=NetUtils.download(toPublish.getPublicLink(false));
|
||||
|
||||
log.debug("Publishing metadata {} ",filename);
|
||||
|
||||
MetadataPublishOptions opts=new MetadataPublishOptions(
|
||||
new TemplateInvocationBuilder().threddsOnlineResources(threddsHostname, filename, publicPath).get());
|
||||
opts.setGeonetworkCategory("Datasets");
|
||||
opts.setValidate(validate);
|
||||
return meta.pushMetadata(tempMetaFile, opts);
|
||||
}catch(Throwable t) {
|
||||
if(tempMetaFile!=null) Files.deleteIfExists(tempMetaFile.toPath());
|
||||
throw new Exception("Something went wrong while publishing metadata for "+filename+". Cause : "+t.getMessage(),t);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static final WorkspaceItem getFileByName(WorkspaceFolder toLookIntoFolder,boolean recursive,String toLookForName) throws InternalErrorException {
|
||||
log.debug("Looking for {} into {} [recursive {} ]",toLookForName,toLookIntoFolder.getPath()+" ID "+toLookIntoFolder.getId(),recursive);
|
||||
for(WorkspaceItem item : toLookIntoFolder.getChildren())
|
||||
if(!item.isFolder()&&item.getName().equals(toLookForName)) return item;
|
||||
|
||||
if(recursive) {
|
||||
for(WorkspaceItem item : toLookIntoFolder.getChildren())
|
||||
if(item.isFolder()) return getFileByName((WorkspaceFolder) item, recursive, toLookForName);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
package org.gcube.usecases.ws.thredds.engine.impl.threads;
|
||||
|
||||
import org.gcube.common.homelibrary.home.workspace.WorkspaceFolder;
|
||||
import org.gcube.common.homelibrary.home.workspace.WorkspaceItem;
|
||||
import org.gcube.usecases.ws.thredds.engine.impl.Process;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class TransferFromThreddsRequest extends SynchronizationRequest {
|
||||
|
||||
private WorkspaceItem targetItem; // can be null
|
||||
|
||||
private String remoteFilename;
|
||||
|
||||
public TransferFromThreddsRequest(Process process, WorkspaceItem targetItem, WorkspaceFolder containingFolder,
|
||||
String remoteFilename) {
|
||||
super(process,containingFolder);
|
||||
this.targetItem = targetItem;
|
||||
this.remoteFilename = remoteFilename;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
package org.gcube.usecases.ws.thredds.engine.impl.threads;
|
||||
|
||||
import org.gcube.common.homelibrary.home.workspace.WorkspaceFolder;
|
||||
import org.gcube.common.homelibrary.home.workspace.WorkspaceItem;
|
||||
import org.gcube.usecases.ws.thredds.engine.impl.Process;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
|
||||
public class TransferToThreddsRequest extends SynchronizationRequest {
|
||||
|
||||
private WorkspaceItem toTransfer;
|
||||
|
||||
public TransferToThreddsRequest(Process process,WorkspaceFolder location, WorkspaceItem toTransfer) {
|
||||
super(process,location);
|
||||
this.toTransfer = toTransfer;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
package org.gcube.usecases.ws.thredds.faults;
|
||||
|
||||
public class CancellationException extends Exception {
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = 736538914489728352L;
|
||||
|
||||
public CancellationException() {
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
public CancellationException(String message) {
|
||||
super(message);
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
public CancellationException(Throwable cause) {
|
||||
super(cause);
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
public CancellationException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
public CancellationException(String message, Throwable cause, boolean enableSuppression,
|
||||
boolean writableStackTrace) {
|
||||
super(message, cause, enableSuppression, writableStackTrace);
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
package org.gcube.usecases.ws.thredds.faults;
|
||||
|
||||
public class DataTransferPluginError extends Exception {
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = 5928532367397696543L;
|
||||
|
||||
public DataTransferPluginError() {
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
public DataTransferPluginError(String message) {
|
||||
super(message);
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
public DataTransferPluginError(Throwable cause) {
|
||||
super(cause);
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
public DataTransferPluginError(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
public DataTransferPluginError(String message, Throwable cause, boolean enableSuppression,
|
||||
boolean writableStackTrace) {
|
||||
super(message, cause, enableSuppression, writableStackTrace);
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
package org.gcube.usecases.ws.thredds.faults;
|
||||
|
||||
public class InternalException extends Exception {
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = 3088246150497872471L;
|
||||
|
||||
public InternalException() {
|
||||
super();
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
public InternalException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
|
||||
super(message, cause, enableSuppression, writableStackTrace);
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
public InternalException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
public InternalException(String message) {
|
||||
super(message);
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
public InternalException(Throwable cause) {
|
||||
super(cause);
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
package org.gcube.usecases.ws.thredds.faults;
|
||||
|
||||
public class LockNotOwnedException extends InternalException {
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = 96212116766290884L;
|
||||
|
||||
public LockNotOwnedException() {
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
public LockNotOwnedException(String message, Throwable cause, boolean enableSuppression,
|
||||
boolean writableStackTrace) {
|
||||
super(message, cause, enableSuppression, writableStackTrace);
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
public LockNotOwnedException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
public LockNotOwnedException(String message) {
|
||||
super(message);
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
public LockNotOwnedException(Throwable cause) {
|
||||
super(cause);
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
package org.gcube.usecases.ws.thredds.faults;
|
||||
|
||||
public class ProcessNotFoundException extends Exception {
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public ProcessNotFoundException() {
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
public ProcessNotFoundException(String message) {
|
||||
super(message);
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
public ProcessNotFoundException(Throwable cause) {
|
||||
super(cause);
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
public ProcessNotFoundException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
public ProcessNotFoundException(String message, Throwable cause, boolean enableSuppression,
|
||||
boolean writableStackTrace) {
|
||||
super(message, cause, enableSuppression, writableStackTrace);
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
package org.gcube.usecases.ws.thredds.faults;
|
||||
|
||||
public class RemoteFileNotFoundException extends InternalException {
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = -4333525223191661141L;
|
||||
|
||||
public RemoteFileNotFoundException() {
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
public RemoteFileNotFoundException(String message, Throwable cause, boolean enableSuppression,
|
||||
boolean writableStackTrace) {
|
||||
super(message, cause, enableSuppression, writableStackTrace);
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
public RemoteFileNotFoundException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
public RemoteFileNotFoundException(String message) {
|
||||
super(message);
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
public RemoteFileNotFoundException(Throwable cause) {
|
||||
super(cause);
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
package org.gcube.usecases.ws.thredds.faults;
|
||||
|
||||
public class UnableToLockException extends InternalException {
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = -6926321942546668032L;
|
||||
|
||||
public UnableToLockException() {
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
public UnableToLockException(String message, Throwable cause, boolean enableSuppression,
|
||||
boolean writableStackTrace) {
|
||||
super(message, cause, enableSuppression, writableStackTrace);
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
public UnableToLockException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
public UnableToLockException(String message) {
|
||||
super(message);
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
public UnableToLockException(Throwable cause) {
|
||||
super(cause);
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
package org.gcube.usecases.ws.thredds.faults;
|
||||
|
||||
public class WorkspaceFolderNotRootException extends WorkspaceInteractionException {
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = 5025376971995804122L;
|
||||
|
||||
public WorkspaceFolderNotRootException() {
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
public WorkspaceFolderNotRootException(String message, Throwable cause, boolean enableSuppression,
|
||||
boolean writableStackTrace) {
|
||||
super(message, cause, enableSuppression, writableStackTrace);
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
public WorkspaceFolderNotRootException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
public WorkspaceFolderNotRootException(String message) {
|
||||
super(message);
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
public WorkspaceFolderNotRootException(Throwable cause) {
|
||||
super(cause);
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
package org.gcube.usecases.ws.thredds.faults;
|
||||
|
||||
public class WorkspaceInteractionException extends Exception {
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = -1121867242282602650L;
|
||||
|
||||
public WorkspaceInteractionException() {
|
||||
super();
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
public WorkspaceInteractionException(String message, Throwable cause, boolean enableSuppression,
|
||||
boolean writableStackTrace) {
|
||||
super(message, cause, enableSuppression, writableStackTrace);
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
public WorkspaceInteractionException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
public WorkspaceInteractionException(String message) {
|
||||
super(message);
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
public WorkspaceInteractionException(Throwable cause) {
|
||||
super(cause);
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
package org.gcube.usecases.ws.thredds.faults;
|
||||
|
||||
public class WorkspaceLockedException extends WorkspaceInteractionException {
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = 4220255895750039163L;
|
||||
|
||||
public WorkspaceLockedException() {
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
public WorkspaceLockedException(String message, Throwable cause, boolean enableSuppression,
|
||||
boolean writableStackTrace) {
|
||||
super(message, cause, enableSuppression, writableStackTrace);
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
public WorkspaceLockedException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
public WorkspaceLockedException(String message) {
|
||||
super(message);
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
public WorkspaceLockedException(Throwable cause) {
|
||||
super(cause);
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
package org.gcube.usecases.ws.thredds.faults;
|
||||
|
||||
public class WorkspaceNotSynchedException extends WorkspaceInteractionException {
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = -321145123900245553L;
|
||||
|
||||
public WorkspaceNotSynchedException() {
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
public WorkspaceNotSynchedException(String message, Throwable cause, boolean enableSuppression,
|
||||
boolean writableStackTrace) {
|
||||
super(message, cause, enableSuppression, writableStackTrace);
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
public WorkspaceNotSynchedException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
public WorkspaceNotSynchedException(String message) {
|
||||
super(message);
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
public WorkspaceNotSynchedException(Throwable cause) {
|
||||
super(cause);
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
package org.gcube.usecases.ws.thredds.model;
|
||||
|
||||
import org.gcube.usecases.ws.thredds.engine.impl.Process;
|
||||
|
||||
public interface CompletionCallback {
|
||||
|
||||
public void onProcessCompleted(Process completedProcess);
|
||||
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
package org.gcube.usecases.ws.thredds.model;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
public class StepReport {
|
||||
|
||||
public static enum Status{
|
||||
ERROR,OK,CANCELLED
|
||||
}
|
||||
|
||||
|
||||
public static enum OperationType{
|
||||
WS_TO_TH,TH_TO_WS,DELETE_REMOTE
|
||||
}
|
||||
|
||||
private String elementName;
|
||||
private String message;
|
||||
private Status status;
|
||||
private OperationType operationType;
|
||||
private long completionTime;
|
||||
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
package org.gcube.usecases.ws.thredds.model;
|
||||
|
||||
import org.gcube.usecases.ws.thredds.engine.impl.ProcessDescriptor;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.NonNull;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
@Data
|
||||
@RequiredArgsConstructor
|
||||
public class SyncFolderDescriptor {
|
||||
|
||||
@NonNull
|
||||
private String folderId;
|
||||
@NonNull
|
||||
private String folderPath;
|
||||
@NonNull
|
||||
private SynchFolderConfiguration configuration;
|
||||
@NonNull
|
||||
private boolean isLocked=false;
|
||||
|
||||
|
||||
private ProcessDescriptor localProcessDescriptor=null;
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
package org.gcube.usecases.ws.thredds.model;
|
||||
|
||||
import org.gcube.usecases.ws.thredds.engine.impl.ProcessDescriptor;
|
||||
import org.gcube.usecases.ws.thredds.engine.impl.ProcessStatus;
|
||||
|
||||
public interface SyncOperationCallBack {
|
||||
|
||||
public void onStep(ProcessStatus status, ProcessDescriptor descriptor);
|
||||
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
package org.gcube.usecases.ws.thredds.model;
|
||||
|
||||
public class SyncOperationTicket {
|
||||
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
package org.gcube.usecases.ws.thredds.model;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.NonNull;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@RequiredArgsConstructor
|
||||
public class SynchFolderConfiguration {
|
||||
|
||||
@NonNull
|
||||
private String remotePath;
|
||||
@NonNull
|
||||
private String filter;
|
||||
@NonNull
|
||||
private String targetToken;
|
||||
|
||||
|
||||
@NonNull
|
||||
private String toCreateCatalogName;
|
||||
|
||||
private String remotePersistence="thredds";
|
||||
|
||||
@NonNull
|
||||
private Boolean validateMetadata=true;
|
||||
|
||||
@NonNull
|
||||
private String rootFolderId;
|
||||
|
||||
public boolean matchesFilter(String name) {
|
||||
return name.endsWith(".nc")||name.endsWith(".ncml")||name.endsWith(".asc");
|
||||
}
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
package org.gcube.usecases.ws.thredds.model;
|
||||
|
||||
public class SynchronizedElementInfo {
|
||||
|
||||
public static enum SynchronizationStatus{
|
||||
UP_TO_DATE,OUTDATED_WS,OUTDATED_REMOTE
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,43 @@
|
||||
package org.gcube.usecases.ws.thredds.model.gui;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@AllArgsConstructor
|
||||
@ToString
|
||||
public class CatalogBean {
|
||||
|
||||
private String name;
|
||||
private String path;
|
||||
private Boolean isDefault;
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((path == null) ? 0 : path.hashCode());
|
||||
return result;
|
||||
}
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
CatalogBean other = (CatalogBean) obj;
|
||||
if (path == null) {
|
||||
if (other.path != null)
|
||||
return false;
|
||||
} else if (!path.equals(other.path))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
# Root logger option
|
||||
#log4j.rootLogger=INFO, SM
|
||||
log4j.logger.org.gcube.usecases.ws=DEBUG,SM
|
||||
|
||||
|
||||
|
||||
#SM-specific logger with dedicated appender
|
||||
log4j.appender.SM=org.apache.log4j.ConsoleAppender
|
||||
log4j.appender.SM.Target=System.out
|
||||
log4j.appender.SM.layout=org.apache.log4j.PatternLayout
|
||||
log4j.appender.SM.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n
|
@ -0,0 +1,6 @@
|
||||
scanner.pool.maxSize=10
|
||||
scanner.pool.coreSize=1
|
||||
scanner.pool.idle.ms=30000
|
||||
transfers.pool.maxSize=40
|
||||
transfers.pool.coreSize=1
|
||||
transfers.pool.idle.ms=30000
|
@ -0,0 +1,78 @@
|
||||
package org.gcube.usecases.ws.thredds;
|
||||
|
||||
import java.util.concurrent.Semaphore;
|
||||
|
||||
import org.gcube.usecases.ws.thredds.engine.impl.ProcessDescriptor;
|
||||
import org.gcube.usecases.ws.thredds.engine.impl.ProcessStatus;
|
||||
import org.gcube.usecases.ws.thredds.faults.InternalException;
|
||||
import org.gcube.usecases.ws.thredds.faults.ProcessNotFoundException;
|
||||
import org.gcube.usecases.ws.thredds.faults.WorkspaceInteractionException;
|
||||
import org.gcube.usecases.ws.thredds.faults.WorkspaceNotSynchedException;
|
||||
import org.gcube.usecases.ws.thredds.model.SyncOperationCallBack;
|
||||
import org.gcube.usecases.ws.thredds.model.SynchFolderConfiguration;
|
||||
|
||||
public class DTSynchUseCase {
|
||||
|
||||
public static void main(String[] args) throws WorkspaceInteractionException, InternalException, ProcessNotFoundException {
|
||||
TokenSetter.set("/d4science.research-infrastructures.eu");
|
||||
SyncEngine engine=SyncEngine.get();
|
||||
|
||||
String folderId="a8cd78d3-69e8-4d02-ac90-681b2d16d84d";
|
||||
|
||||
|
||||
// String folderId="8a6f9749-68d7-4a9a-a475-bd645050c3fd"; // sub folder for faster tests
|
||||
System.out.println("Clearing configuration.. ");
|
||||
|
||||
try {
|
||||
engine.unsetSynchronizedFolder(folderId, false);
|
||||
}catch(WorkspaceNotSynchedException e) {
|
||||
|
||||
}
|
||||
System.out.println("Setting configuration");
|
||||
|
||||
|
||||
SynchFolderConfiguration config=new SynchFolderConfiguration("public/netcdf/GPTest", "",
|
||||
"f851ba11-bd3e-417a-b2c2-753b02bac506-98187548", // devVRE
|
||||
"Agro",folderId);
|
||||
|
||||
engine.setSynchronizedFolder(config, folderId);
|
||||
|
||||
System.out.println("Invoke check... ");
|
||||
engine.check(folderId, false);
|
||||
|
||||
|
||||
|
||||
System.out.println("Invoke synch");
|
||||
|
||||
engine.doSync(folderId);
|
||||
|
||||
Semaphore sem=new Semaphore(0);
|
||||
|
||||
engine.registerCallBack(folderId, new SyncOperationCallBack() {
|
||||
|
||||
@Override
|
||||
public void onStep(ProcessStatus status, ProcessDescriptor descriptor) {
|
||||
System.out.println("ON STEP : "+status+" "+descriptor);
|
||||
System.out.println("LOG : \n"+ status.getLogBuilder().toString());
|
||||
if(status.getStatus().equals(ProcessStatus.Status.COMPLETED)) sem.release();
|
||||
}
|
||||
});
|
||||
|
||||
System.out.println("Waiting for process.. ");
|
||||
try {
|
||||
sem.acquire();
|
||||
} catch (InterruptedException e) {
|
||||
|
||||
}
|
||||
|
||||
System.out.println("Done");
|
||||
|
||||
engine.check(folderId, false);
|
||||
|
||||
|
||||
// INVOKE WHEN PORTAL SHUTS DOWN TO FREE RESOURCES AND STOP SYNC PROCESSES
|
||||
engine.shutDown();
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,67 @@
|
||||
package org.gcube.usecases.ws.thredds;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.Collections;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.gcube.common.homelibrary.home.HomeLibrary;
|
||||
import org.gcube.common.homelibrary.home.exceptions.HomeNotFoundException;
|
||||
import org.gcube.common.homelibrary.home.exceptions.InternalErrorException;
|
||||
import org.gcube.common.homelibrary.home.exceptions.UserNotFoundException;
|
||||
import org.gcube.common.homelibrary.home.workspace.Workspace;
|
||||
import org.gcube.common.homelibrary.home.workspace.exceptions.ItemNotFoundException;
|
||||
import org.gcube.common.homelibrary.home.workspace.exceptions.WorkspaceFolderNotFoundException;
|
||||
import org.gcube.data.transfer.library.DataTransferClient;
|
||||
import org.gcube.data.transfer.library.faults.DestinationNotSetException;
|
||||
import org.gcube.data.transfer.library.faults.FailedTransferException;
|
||||
import org.gcube.data.transfer.library.faults.InitializationException;
|
||||
import org.gcube.data.transfer.library.faults.InvalidDestinationException;
|
||||
import org.gcube.data.transfer.library.faults.InvalidSourceException;
|
||||
import org.gcube.data.transfer.library.faults.ServiceNotFoundException;
|
||||
import org.gcube.data.transfer.library.faults.SourceNotSetException;
|
||||
import org.gcube.data.transfer.library.faults.UnreachableNodeException;
|
||||
import org.gcube.data.transfer.model.Destination;
|
||||
import org.gcube.data.transfer.model.DestinationClashPolicy;
|
||||
import org.gcube.data.transfer.model.PluginInvocation;
|
||||
import org.gcube.usecases.ws.thredds.faults.InternalException;
|
||||
import org.gcube.usecases.ws.thredds.faults.WorkspaceInteractionException;
|
||||
import org.gcube.usecases.ws.thredds.model.SynchFolderConfiguration;
|
||||
|
||||
public class DTTests {
|
||||
|
||||
public static void main(String[] args) throws InvalidSourceException, SourceNotSetException, FailedTransferException, InitializationException, InvalidDestinationException, DestinationNotSetException, MalformedURLException, FileNotFoundException, IOException, WorkspaceInteractionException, InternalException, WorkspaceFolderNotFoundException, InternalErrorException, HomeNotFoundException, UserNotFoundException, ItemNotFoundException {
|
||||
// TestCommons.setScope();
|
||||
// String threddsHostname="thredds-d-d4s.d4science.org";
|
||||
// DataTransferClient client=DataTransferClient.getInstanceByEndpoint("http://"+threddsHostname+":80");
|
||||
// Destination toSetDestination=new Destination();
|
||||
// toSetDestination.setCreateSubfolders(true);
|
||||
// toSetDestination.setDestinationFileName("transferTest.tst");
|
||||
// toSetDestination.setOnExistingFileName(DestinationClashPolicy.REWRITE);
|
||||
// toSetDestination.setOnExistingSubFolder(DestinationClashPolicy.APPEND);
|
||||
// toSetDestination.setPersistenceId("thredds");
|
||||
//
|
||||
// //NB ITEM IS SUPPOSED TO HAVE REMOTE PATH
|
||||
// String fileLocation="WS-Tests/mySub";
|
||||
// toSetDestination.setSubFolder(fileLocation);
|
||||
//
|
||||
// File temp=File.createTempFile("testTransfer", "tmp");
|
||||
// IOUtils.copy(new URL("http://data-d.d4science.org/SUlDWjIxamdaUTdHcmpvdEFmcFFPOUcvbjF5VyswbXlHbWJQNStIS0N6Yz0").openStream(), new FileOutputStream(temp));
|
||||
//
|
||||
// System.out.println(client.localFile(temp,
|
||||
// toSetDestination,Collections.singleton(new PluginInvocation(Constants.SIS_PLUGIN_ID))));
|
||||
//
|
||||
|
||||
TokenSetter.set("/gcube/devNext");
|
||||
Workspace ws = HomeLibrary.getHomeManagerFactory().getHomeManager().getHome().getWorkspace();
|
||||
String folderId=ws.getItemByPath("/Workspace/Accounting").getId();
|
||||
SyncEngine.get().setSynchronizedFolder(new SynchFolderConfiguration("another", "", TokenSetter.getCurrentToken(), "dummy",folderId), folderId);
|
||||
System.out.println("Done");
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,78 @@
|
||||
package org.gcube.usecases.ws.thredds;
|
||||
|
||||
import org.gcube.usecases.ws.thredds.engine.impl.ThreddsController;
|
||||
import org.gcube.usecases.ws.thredds.faults.InternalException;
|
||||
import org.gcube.usecases.ws.thredds.faults.UnableToLockException;
|
||||
|
||||
public class FileAccessTests {
|
||||
|
||||
public static void main(String[] args) throws InternalException {
|
||||
TestCommons.setScope();
|
||||
String processID="stupidProcess";
|
||||
String toLockFolder="devVRE";
|
||||
|
||||
final ThreddsController controller=new ThreddsController(toLockFolder, TokenSetter.getCurrentToken());
|
||||
|
||||
Runnable readCatalog=new Runnable() {@Override public void run() { try{
|
||||
controller.readThreddsFile("catalog.xml");
|
||||
|
||||
}catch(Throwable t) {System.err.println(t); }}};
|
||||
|
||||
|
||||
Runnable readInfo=new Runnable() {@Override public void run() { try{
|
||||
controller.getThreddsInfo();
|
||||
}catch(Throwable t) {System.err.println(t); }}};
|
||||
|
||||
|
||||
repeatedTimedOperation(readCatalog,"READ CATALOG");
|
||||
|
||||
repeatedTimedOperation(readInfo, "READ INFO");
|
||||
|
||||
|
||||
System.out.println("Checking lock ..");
|
||||
|
||||
|
||||
|
||||
try {
|
||||
controller.lockFolder(processID);
|
||||
}catch(UnableToLockException e) {
|
||||
System.out.println("Dirty from previous tests.. removing lock..");
|
||||
controller.deleteThreddsFile(Constants.LOCK_FILE);
|
||||
System.out.println("Trying to lock again..");
|
||||
controller.lockFolder(processID);
|
||||
}
|
||||
|
||||
try{
|
||||
System.out.println("Reading file descriptor... ");
|
||||
System.out.println(controller.getFileDescriptor(Constants.LOCK_FILE));
|
||||
System.out.println("Ok, next should fail...");
|
||||
controller.lockFolder(processID);
|
||||
}catch(UnableToLockException e) {
|
||||
System.out.println("Correctly failed, now we read lock.. ");
|
||||
|
||||
String lockId=controller.readThreddsFile(Constants.LOCK_FILE);
|
||||
if(lockId.equals(processID)) {
|
||||
System.out.println("Lock owned. Going to remove it.. ");
|
||||
controller.deleteThreddsFile(Constants.LOCK_FILE);
|
||||
System.out.println("Now I can lock it again... ");
|
||||
controller.lockFolder(processID);
|
||||
System.out.println("Ok, cleaning it up.. ");
|
||||
controller.deleteThreddsFile(Constants.LOCK_FILE);
|
||||
}else throw new RuntimeException("LOCK ID "+lockId+" IS DIFFERENT then expected "+processID);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
private static void repeatedTimedOperation(Runnable op,String title) {
|
||||
System.out.println(title);
|
||||
for(int i=0;i<10;i++) {
|
||||
long startTime=System.currentTimeMillis();
|
||||
op.run();
|
||||
System.out.println("["+i+"] in "+(System.currentTimeMillis()-startTime));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
package org.gcube.usecases.ws.thredds;
|
||||
|
||||
import org.gcube.common.homelibrary.home.HomeLibrary;
|
||||
import org.gcube.common.homelibrary.home.exceptions.HomeNotFoundException;
|
||||
import org.gcube.common.homelibrary.home.exceptions.InternalErrorException;
|
||||
import org.gcube.common.homelibrary.home.exceptions.UserNotFoundException;
|
||||
import org.gcube.common.homelibrary.home.workspace.Workspace;
|
||||
import org.gcube.common.homelibrary.home.workspace.WorkspaceFolder;
|
||||
import org.gcube.common.homelibrary.home.workspace.WorkspaceItem;
|
||||
import org.gcube.common.homelibrary.home.workspace.exceptions.ItemNotFoundException;
|
||||
import org.gcube.common.homelibrary.home.workspace.exceptions.WorkspaceFolderNotFoundException;
|
||||
import org.gcube.common.homelibrary.home.workspace.folder.FolderItem;
|
||||
import org.gcube.usecases.ws.thredds.model.SynchFolderConfiguration;
|
||||
|
||||
public class GetWSSynchSpace {
|
||||
|
||||
public static void main(String[] args) throws WorkspaceFolderNotFoundException, InternalErrorException, HomeNotFoundException, UserNotFoundException, ItemNotFoundException {
|
||||
TokenSetter.set("/gcube/preprod/preVRE");
|
||||
SyncEngine engine=SyncEngine.get();
|
||||
|
||||
String folderId=TestCommons.getWSIdByPath("/Workspace/Thredds main catalog");
|
||||
|
||||
System.out.println(folderId);
|
||||
|
||||
|
||||
Workspace ws = HomeLibrary.getHomeManagerFactory().getHomeManager().getHome().getWorkspace();
|
||||
WorkspaceFolder folder=(WorkspaceFolder) ws.getItem(folderId);
|
||||
|
||||
SynchFolderConfiguration config=new SynchFolderConfiguration();
|
||||
System.out.println("Total size : "+computeLength(folder, config));
|
||||
}
|
||||
|
||||
|
||||
private static final long computeLength(WorkspaceItem item,SynchFolderConfiguration config) throws InternalErrorException {
|
||||
long toReturn=0l;
|
||||
if(item.isFolder()) {
|
||||
for(WorkspaceItem child:((WorkspaceFolder)item).getChildren()) {
|
||||
if(item.isFolder()||config.matchesFilter(item.getName()))
|
||||
toReturn=toReturn+computeLength(child, config);
|
||||
}
|
||||
}else toReturn=toReturn+((FolderItem)item).getLength();
|
||||
return toReturn;
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,103 @@
|
||||
package org.gcube.usecases.ws.thredds;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import org.gcube.common.homelibrary.home.HomeLibrary;
|
||||
import org.gcube.common.homelibrary.home.exceptions.HomeNotFoundException;
|
||||
import org.gcube.common.homelibrary.home.exceptions.InternalErrorException;
|
||||
import org.gcube.common.homelibrary.home.exceptions.UserNotFoundException;
|
||||
import org.gcube.common.homelibrary.home.workspace.Properties;
|
||||
import org.gcube.common.homelibrary.home.workspace.Workspace;
|
||||
import org.gcube.common.homelibrary.home.workspace.WorkspaceFolder;
|
||||
import org.gcube.common.homelibrary.home.workspace.WorkspaceItem;
|
||||
import org.gcube.common.homelibrary.home.workspace.exceptions.ItemNotFoundException;
|
||||
import org.gcube.common.homelibrary.home.workspace.exceptions.WorkspaceFolderNotFoundException;
|
||||
import org.gcube.data.transfer.library.DataTransferClient;
|
||||
import org.gcube.data.transfer.library.faults.DestinationNotSetException;
|
||||
import org.gcube.data.transfer.library.faults.FailedTransferException;
|
||||
import org.gcube.data.transfer.library.faults.InitializationException;
|
||||
import org.gcube.data.transfer.library.faults.InvalidDestinationException;
|
||||
import org.gcube.data.transfer.library.faults.InvalidSourceException;
|
||||
import org.gcube.data.transfer.library.faults.SourceNotSetException;
|
||||
import org.gcube.data.transfer.model.Destination;
|
||||
import org.gcube.data.transfer.model.DestinationClashPolicy;
|
||||
import org.gcube.spatial.data.sdi.interfaces.Metadata;
|
||||
import org.gcube.spatial.data.sdi.model.metadata.MetadataPublishOptions;
|
||||
import org.gcube.spatial.data.sdi.model.metadata.MetadataReport;
|
||||
import org.gcube.spatial.data.sdi.model.metadata.TemplateInvocationBuilder;
|
||||
import org.gcube.spatial.data.sdi.plugins.SDIAbstractPlugin;
|
||||
import org.gcube.usecases.ws.thredds.model.SynchFolderConfiguration;
|
||||
|
||||
public class PublicLinkIssueTest {
|
||||
|
||||
|
||||
public static void main (String[] args) throws ItemNotFoundException, InternalErrorException, WorkspaceFolderNotFoundException, HomeNotFoundException, UserNotFoundException, InvalidSourceException, SourceNotSetException, FailedTransferException, InitializationException, InvalidDestinationException, DestinationNotSetException {
|
||||
TokenSetter.set("/d4science.research-infrastructures.eu");
|
||||
|
||||
Workspace ws = HomeLibrary.getHomeManagerFactory().getHomeManager().getHome().getWorkspace();
|
||||
System.out.println(ws.getItemByPath("/Workspace/ArgoNetCDF/Practical_salinity/Practical_salinity_code_30_date_2000_6.nc").getPublicLink(false));
|
||||
|
||||
String threddsHostName = Commons.getThreddsHost();
|
||||
|
||||
DataTransferClient client=Commons.getDTClient(threddsHostName);
|
||||
Destination dest=new Destination("thredds", "public/netcdf/someWhere", "myTest.txt", true, DestinationClashPolicy.REWRITE, DestinationClashPolicy.APPEND);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
client.httpSource("http://data.d4science.org/V2drR2gxSFRTQlpLVC9nakozL29QcDdPR2U5UEVHYWRHbWJQNStIS0N6Yz0", dest);
|
||||
|
||||
|
||||
scanForPrint((WorkspaceFolder) ws.getItem("a8cd78d3-69e8-4d02-ac90-681b2d16d84d"));
|
||||
System.out.println("OK FIRST ...");
|
||||
try {
|
||||
Metadata meta=SDIAbstractPlugin.metadata().build();
|
||||
|
||||
|
||||
|
||||
MetadataPublishOptions opts=new MetadataPublishOptions(new TemplateInvocationBuilder().threddsOnlineResources(threddsHostName, "myMeta", "testCatalog").get());
|
||||
opts.setGeonetworkCategory("Datasets");
|
||||
MetadataReport report=meta.pushMetadata(new File("/home/fabio/Desktop/meta.xml"), opts);
|
||||
}catch(Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
System.out.println("CHECKING AGAIN");
|
||||
scanForPrint((WorkspaceFolder) ws.getItem("a8cd78d3-69e8-4d02-ac90-681b2d16d84d"));
|
||||
|
||||
|
||||
}
|
||||
|
||||
public static void scanForPrint(WorkspaceFolder folder) throws InternalErrorException {
|
||||
System.out.println("Folder "+folder.getPath());
|
||||
printProperties(folder.getProperties());
|
||||
SynchFolderConfiguration config=new SynchFolderConfiguration("", "", "", "","");
|
||||
for(WorkspaceItem item:folder.getChildren())
|
||||
if(!item.isFolder()&&config.matchesFilter(item.getName())) {
|
||||
// System.out.println("ITEM "+item.getPath());
|
||||
printProperties(item.getProperties());
|
||||
}
|
||||
for(WorkspaceItem item:folder.getChildren())
|
||||
if(item.isFolder())scanForPrint((WorkspaceFolder) item);
|
||||
}
|
||||
|
||||
|
||||
public static void printProperties(Properties prop) throws InternalErrorException {
|
||||
Map<String,String> map=prop.getProperties();
|
||||
// System.out.print("Properties : ..");
|
||||
for(Entry<String,String> entry:map.entrySet()) {
|
||||
if(entry.getKey().equals(Constants.WorkspaceProperties.SYNCHRONIZATION_STATUS)||
|
||||
entry.getKey().equals(Constants.WorkspaceProperties.LAST_UPDATE_STATUS)||
|
||||
entry.getKey().equals(Constants.WorkspaceProperties.LAST_UPDATE_TIME)) {
|
||||
// if(true) {
|
||||
if(entry.getValue()==null) System.out.print(entry.getKey()+" is null;");
|
||||
else System.out.print(entry.getKey()+" = "+entry.getValue()+";");
|
||||
}
|
||||
}
|
||||
// System.out.println();
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,113 @@
|
||||
package org.gcube.usecases.ws.thredds;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.MalformedURLException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.gcube.common.homelibrary.home.HomeLibrary;
|
||||
import org.gcube.common.homelibrary.home.exceptions.HomeNotFoundException;
|
||||
import org.gcube.common.homelibrary.home.exceptions.InternalErrorException;
|
||||
import org.gcube.common.homelibrary.home.exceptions.UserNotFoundException;
|
||||
import org.gcube.common.homelibrary.home.workspace.Workspace;
|
||||
import org.gcube.common.homelibrary.home.workspace.WorkspaceFolder;
|
||||
import org.gcube.common.homelibrary.home.workspace.exceptions.InsufficientPrivilegesException;
|
||||
import org.gcube.common.homelibrary.home.workspace.exceptions.ItemAlreadyExistException;
|
||||
import org.gcube.common.homelibrary.home.workspace.exceptions.ItemNotFoundException;
|
||||
import org.gcube.common.homelibrary.home.workspace.exceptions.WorkspaceFolderNotFoundException;
|
||||
import org.gcube.usecases.ws.thredds.engine.impl.ThreddsController;
|
||||
import org.gcube.usecases.ws.thredds.faults.InternalException;
|
||||
import org.gcube.usecases.ws.thredds.model.SynchFolderConfiguration;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
public class TestCommons {
|
||||
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
static class TestSet{
|
||||
String label;
|
||||
String scope;
|
||||
String folderId;
|
||||
String remotePath;
|
||||
String targetToken;
|
||||
String toCreateCatalogName;
|
||||
|
||||
|
||||
public String getFolderId() throws WorkspaceFolderNotFoundException, ItemNotFoundException, InternalErrorException, HomeNotFoundException, UserNotFoundException {
|
||||
if(folderId.startsWith("/"))
|
||||
return getWSIdByPath(folderId);
|
||||
else return folderId;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static Map<String,TestSet> configs=new HashMap<>();
|
||||
|
||||
private static String toUseConfig="pre";
|
||||
|
||||
|
||||
static {
|
||||
|
||||
configs.put("GP", new TestSet("GPTests","/d4science.research-infrastructures.eu","a8cd78d3-69e8-4d02-ac90-681b2d16d84d","","",""));
|
||||
|
||||
// folderName="WS-Tests";
|
||||
|
||||
configs.put("default", new TestSet("Default Tests","/gcube/devsec/devVRE","/Workspace/ThreddsDev","public/netcdf","f851ba11-bd3e-417a-b2c2-753b02bac506-98187548","main"));
|
||||
|
||||
|
||||
configs.put("pre", new TestSet("Default Tests","/gcube/preprod/preVRE","/Workspace/CMEMS","public/netcdf/CMEMS","97cfc53e-7f71-4676-b5e0-bdd149c8460f-98187548","main"));
|
||||
|
||||
}
|
||||
|
||||
|
||||
public static String getWSIdByPath(String path) throws WorkspaceFolderNotFoundException, InternalErrorException, HomeNotFoundException, UserNotFoundException, ItemNotFoundException {
|
||||
Workspace ws = HomeLibrary.getHomeManagerFactory().getHomeManager().getHome().getWorkspace();
|
||||
return ws.getItemByPath(path).getId();
|
||||
}
|
||||
|
||||
|
||||
public static void setScope() {
|
||||
TokenSetter.set(configs.get(toUseConfig).getScope());
|
||||
}
|
||||
|
||||
|
||||
public static WorkspaceFolder getTestFolder() throws WorkspaceFolderNotFoundException, InternalErrorException, HomeNotFoundException, UserNotFoundException, ItemNotFoundException, InsufficientPrivilegesException, ItemAlreadyExistException, MalformedURLException, IOException {
|
||||
Workspace ws = HomeLibrary.getHomeManagerFactory().getHomeManager().getHome().getWorkspace();
|
||||
try{
|
||||
return (WorkspaceFolder) ws.getItem(configs.get(toUseConfig).getFolderId());
|
||||
}catch(Throwable t) {
|
||||
// try to use path
|
||||
return (WorkspaceFolder) ws.getItemByPath(configs.get(toUseConfig).getFolderId());
|
||||
}
|
||||
|
||||
|
||||
|
||||
// WorkspaceFolder folder=null;
|
||||
// try{
|
||||
// folder=ws.getRoot().createFolder(folderName+"2", "test purposes");
|
||||
// }catch(ClassCastException e) {
|
||||
// folder=(WorkspaceFolder) ws.getItemByPath("/Workspace/"+folderName+"2");
|
||||
// }
|
||||
//
|
||||
// String datasetUrl="https://thredds-d-d4s.d4science.org/thredds/fileServer/public/netcdf/test%20by%20Francesco/dissolved_oxygen_annual_5deg_ENVIRONMENT_BIOTA_.nc";
|
||||
// try {
|
||||
// folder.createExternalFileItem("dissolved_oxygen_annual_5deg_ENVIRONMENT_BIOTA_.nc", "nc test file", "application/x-netcdf", new URL(datasetUrl).openStream());
|
||||
// }catch(Exception e) {
|
||||
// // file already existing..
|
||||
// }
|
||||
// return folder;
|
||||
}
|
||||
|
||||
|
||||
public static ThreddsController getThreddsController() throws InternalException, WorkspaceFolderNotFoundException, ItemNotFoundException, InternalErrorException, HomeNotFoundException, UserNotFoundException {
|
||||
SynchFolderConfiguration config=getSynchConfig();
|
||||
return new ThreddsController(config.getRemotePath(), config.getTargetToken());
|
||||
}
|
||||
|
||||
public static SynchFolderConfiguration getSynchConfig() throws WorkspaceFolderNotFoundException, ItemNotFoundException, InternalErrorException, HomeNotFoundException, UserNotFoundException {
|
||||
TestSet set=configs.get(toUseConfig);
|
||||
return new SynchFolderConfiguration(set.getRemotePath(), "*.nc,*.ncml,*.asc", set.getTargetToken(),set.getToCreateCatalogName(),set.getFolderId());
|
||||
}
|
||||
}
|
@ -0,0 +1,71 @@
|
||||
package org.gcube.usecases.ws.thredds;
|
||||
|
||||
import org.gcube.data.transfer.library.utils.ScopeUtils;
|
||||
import org.gcube.data.transfer.model.plugins.thredds.DataSetScan;
|
||||
import org.gcube.data.transfer.model.plugins.thredds.ThreddsInfo;
|
||||
import org.gcube.usecases.ws.thredds.engine.impl.ThreddsController;
|
||||
import org.gcube.usecases.ws.thredds.faults.InternalException;
|
||||
|
||||
public class ThreddsCatalogTests {
|
||||
|
||||
public static void main(String[] args) throws InternalException {
|
||||
TokenSetter.set("/gcube/devsec");
|
||||
|
||||
System.out.println("Current scope is "+ScopeUtils.getCurrentScope());
|
||||
|
||||
// SyncEngine engine=SyncEngine.get();
|
||||
//
|
||||
// String[] toCheckTokens=new String[] {
|
||||
// "123da564-2af2-4023-90f5-01a934d80754-98187548",
|
||||
// "678abd6f-1a39-4e52-9c14-9288bf28a2ed-98187548",
|
||||
// "f851ba11-bd3e-417a-b2c2-753b02bac506-98187548",
|
||||
// "1dd10a45-4b04-4fba-b878-ed6e40d235db-843339462",
|
||||
// "feda0617-cd9d-4841-b6f0-e047da5d32ed-98187548",
|
||||
// "5741e3e4-dbde-46fa-828d-88da609e0517-98187548",
|
||||
// "97cfc53e-7f71-4676-b5e0-bdd149c8460f-98187548",
|
||||
// "6a16458f-d514-4c83-b012-6f2b6bf19794-843339462",
|
||||
// "84bcb500-100e-4d35-868d-d6f3dbb95ade-843339462",
|
||||
// "9dd56598-4092-460d-bfe4-91ecff66290a-843339462",
|
||||
// "adb3f8f5-bf55-4d31-b951-c60139ff8b85-843339462",
|
||||
// "39f574c0-d439-4c29-a652-01d97472a4fb-843339462",
|
||||
// "3701435c-1c36-494f-ae31-4d002910e27e-843339462",
|
||||
// "cc491b9c-c75b-41a8-a999-4c9f6f25263d-843339462",
|
||||
// "74673327-645e-4b0b-8382-2edd663f3a38-843339462",
|
||||
// "65f3fc8b-1bcc-4ae7-a71f-97e671a27cb7-843339462",
|
||||
// "3240d5ec-72e6-4e03-b0c7-eaa24d91ea80-843339462",
|
||||
// };
|
||||
//
|
||||
//
|
||||
// for(String token:toCheckTokens) {
|
||||
// System.out.println("Checking catalog for token "+token);
|
||||
// for(CatalogBean bean:engine.getAvailableCatalogsByToken(token))
|
||||
// System.out.println(bean.getName()+" in "+bean.getPath()+" Default : "+bean.getIsDefault());
|
||||
//
|
||||
// System.out.println("************************************");
|
||||
// System.out.println();
|
||||
// }
|
||||
//
|
||||
|
||||
|
||||
ThreddsController controller=new ThreddsController("",TokenSetter.getCurrentToken());
|
||||
|
||||
ThreddsInfo info=controller.getThreddsInfo();
|
||||
String [] paths=new String[] {
|
||||
"/data/content/thredds/newer",
|
||||
"/data/content/thredds/public",
|
||||
"/data/content/thredds/public/netcdf",
|
||||
"/data/content/thredds/public/netcdf/GPTest",
|
||||
};
|
||||
|
||||
for(String path:paths) {
|
||||
if(info.getCatalogByFittingLocation(path)!=null) {
|
||||
DataSetScan ds=(DataSetScan) info.getDataSetFromLocation(path);
|
||||
if(ds==null)
|
||||
System.out.println("Catalog for "+path+"\t is null.");
|
||||
else System.out.println("Catalog for "+path+"\t : "+ds.getLocation()+"\t "+ds.getName());
|
||||
}else System.out.println("No catalog for path "+path);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
package org.gcube.usecases.ws.thredds;
|
||||
|
||||
import org.gcube.common.homelibrary.home.exceptions.HomeNotFoundException;
|
||||
import org.gcube.common.homelibrary.home.exceptions.InternalErrorException;
|
||||
import org.gcube.common.homelibrary.home.exceptions.UserNotFoundException;
|
||||
import org.gcube.common.homelibrary.home.workspace.exceptions.ItemNotFoundException;
|
||||
import org.gcube.common.homelibrary.home.workspace.exceptions.WorkspaceFolderNotFoundException;
|
||||
import org.gcube.data.transfer.model.plugins.thredds.ThreddsInfo;
|
||||
import org.gcube.usecases.ws.thredds.engine.impl.ThreddsController;
|
||||
import org.gcube.usecases.ws.thredds.faults.InternalException;
|
||||
import org.gcube.usecases.ws.thredds.model.SynchFolderConfiguration;
|
||||
|
||||
public class ThreddsTests {
|
||||
|
||||
public static void main(String[] args) throws InternalException, WorkspaceFolderNotFoundException, ItemNotFoundException, InternalErrorException, HomeNotFoundException, UserNotFoundException {
|
||||
TestCommons.setScope();
|
||||
|
||||
SynchFolderConfiguration folderConfig=TestCommons.getSynchConfig();
|
||||
ThreddsController controller=TestCommons.getThreddsController();
|
||||
|
||||
System.out.println("Getting thredds info...");
|
||||
|
||||
ThreddsInfo info=controller.getThreddsInfo();
|
||||
|
||||
System.out.println("INFO "+info);
|
||||
|
||||
System.out.println(info.getCatalogByFittingLocation(info.getLocalBasePath()+"/"+folderConfig.getRemotePath()));
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
package org.gcube.usecases.ws.thredds;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.MalformedURLException;
|
||||
|
||||
import org.gcube.common.homelibrary.home.exceptions.HomeNotFoundException;
|
||||
import org.gcube.common.homelibrary.home.exceptions.InternalErrorException;
|
||||
import org.gcube.common.homelibrary.home.exceptions.UserNotFoundException;
|
||||
import org.gcube.common.homelibrary.home.workspace.WorkspaceFolder;
|
||||
import org.gcube.common.homelibrary.home.workspace.WorkspaceItem;
|
||||
import org.gcube.common.homelibrary.home.workspace.exceptions.InsufficientPrivilegesException;
|
||||
import org.gcube.common.homelibrary.home.workspace.exceptions.ItemAlreadyExistException;
|
||||
import org.gcube.common.homelibrary.home.workspace.exceptions.ItemNotFoundException;
|
||||
import org.gcube.common.homelibrary.home.workspace.exceptions.WorkspaceFolderNotFoundException;
|
||||
|
||||
public class WSTimes {
|
||||
|
||||
public static void main(String[] args) throws WorkspaceFolderNotFoundException, ItemNotFoundException, InsufficientPrivilegesException, ItemAlreadyExistException, MalformedURLException, InternalErrorException, HomeNotFoundException, UserNotFoundException, IOException {
|
||||
TestCommons.setScope();
|
||||
WorkspaceFolder folder=TestCommons.getTestFolder();
|
||||
for(WorkspaceItem item : folder.getChildren()) {
|
||||
printDates(item);
|
||||
try {
|
||||
Thread.sleep(3000);
|
||||
} catch (InterruptedException e) {
|
||||
|
||||
}
|
||||
item.getProperties().addProperty("Fake prop", "fake value");
|
||||
printDates(item);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static final void printDates(WorkspaceItem item) throws InternalErrorException {
|
||||
System.out.println("ITEM : "+item.getName());
|
||||
System.out.println("Creation Date : "+Constants.DATE_FORMAT.format(item.getCreationTime().getTime()));
|
||||
System.out.println("Creation Date : "+Constants.DATE_FORMAT.format(item.getLastModificationTime().getTime()));
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,75 @@
|
||||
package org.gcube.usecases.ws.thredds;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Date;
|
||||
|
||||
import org.gcube.common.homelibrary.home.HomeLibrary;
|
||||
import org.gcube.common.homelibrary.home.exceptions.HomeNotFoundException;
|
||||
import org.gcube.common.homelibrary.home.exceptions.InternalErrorException;
|
||||
import org.gcube.common.homelibrary.home.exceptions.UserNotFoundException;
|
||||
import org.gcube.common.homelibrary.home.workspace.Workspace;
|
||||
import org.gcube.common.homelibrary.home.workspace.exceptions.InsufficientPrivilegesException;
|
||||
import org.gcube.common.homelibrary.home.workspace.exceptions.ItemAlreadyExistException;
|
||||
import org.gcube.common.homelibrary.home.workspace.exceptions.ItemNotFoundException;
|
||||
import org.gcube.common.homelibrary.home.workspace.exceptions.WorkspaceFolderNotFoundException;
|
||||
import org.gcube.usecases.ws.thredds.engine.impl.WorkspaceUtils;
|
||||
|
||||
public class WorkspaceAccounting {
|
||||
|
||||
public static void main(String[] args) throws InsufficientPrivilegesException, ItemAlreadyExistException, InternalErrorException, IOException, WorkspaceFolderNotFoundException, HomeNotFoundException, UserNotFoundException, NumberFormatException, ItemNotFoundException {
|
||||
TestCommons.setScope();
|
||||
Workspace ws = HomeLibrary.getHomeManagerFactory().getHomeManager().getHome().getWorkspace();
|
||||
|
||||
|
||||
// WorkspaceFolder folder=ws.getRoot().createFolder("Accounting", "test purposes");
|
||||
//
|
||||
//
|
||||
// WorkspaceFolder subFolder=folder.createFolder("SubFolder", "Will be removed");
|
||||
//
|
||||
//
|
||||
// ExternalFile toBeRemovedFile=folder.createExternalFileItem("The file", "file to be removed", "application/xml", File.createTempFile("tmp", ".tmp"));
|
||||
//
|
||||
// subFolder.remove();
|
||||
// toBeRemovedFile.remove();
|
||||
//
|
||||
//
|
||||
// for(AccountingEntry entry:folder.getAccounting()) {
|
||||
// try {
|
||||
//
|
||||
//
|
||||
// Date eventTime=entry.getDate().getTime();
|
||||
// String toDeleteRemote=null;
|
||||
// switch(entry.getEntryType()) {
|
||||
// case REMOVAL:{
|
||||
// AccountingEntryRemoval removalEntry=(AccountingEntryRemoval) entry;
|
||||
// System.out.println(removalEntry.getItemName() +"REMOVED. FolderItemType "+removalEntry.getFolderItemType()+" ItemType "+removalEntry.getItemType());
|
||||
//
|
||||
//
|
||||
// break;
|
||||
// }
|
||||
// case RENAMING:{
|
||||
// AccountingEntryRenaming renamingEntry=(AccountingEntryRenaming) entry;
|
||||
// toDeleteRemote=renamingEntry.getOldItemName();
|
||||
//
|
||||
// }
|
||||
// case CUT:{
|
||||
// AccountingEntryCut cut = (AccountingEntryCut) entry;
|
||||
// toDeleteRemote=cut.getItemName();
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// }catch(Throwable t) {
|
||||
// t.printStackTrace();
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// }
|
||||
|
||||
|
||||
|
||||
System.out.println(WorkspaceUtils.isModifiedAfter(ws.getItemByPath(TestCommons.getTestFolder().getPath()+"/mySub/dissolved_oxygen_annual_5deg_ENVIRONMENT_BIOTA_.nc"), new Date(0l)));
|
||||
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
package org.gcube.usecases.ws.thredds;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.MalformedURLException;
|
||||
|
||||
import org.gcube.common.homelibrary.home.exceptions.HomeNotFoundException;
|
||||
import org.gcube.common.homelibrary.home.exceptions.InternalErrorException;
|
||||
import org.gcube.common.homelibrary.home.exceptions.UserNotFoundException;
|
||||
import org.gcube.common.homelibrary.home.workspace.WorkspaceFolder;
|
||||
import org.gcube.common.homelibrary.home.workspace.exceptions.InsufficientPrivilegesException;
|
||||
import org.gcube.common.homelibrary.home.workspace.exceptions.ItemAlreadyExistException;
|
||||
import org.gcube.common.homelibrary.home.workspace.exceptions.ItemNotFoundException;
|
||||
import org.gcube.common.homelibrary.home.workspace.exceptions.WorkspaceFolderNotFoundException;
|
||||
import org.gcube.usecases.ws.thredds.faults.InternalException;
|
||||
import org.gcube.usecases.ws.thredds.faults.WorkspaceInteractionException;
|
||||
|
||||
public class WorkspaceCleanup {
|
||||
|
||||
public static void main(String[] args) throws WorkspaceInteractionException, InternalException, InternalErrorException, WorkspaceFolderNotFoundException, ItemNotFoundException, InsufficientPrivilegesException, ItemAlreadyExistException, MalformedURLException, HomeNotFoundException, UserNotFoundException, IOException {
|
||||
TestCommons.setScope();
|
||||
WorkspaceFolder folder=TestCommons.getTestFolder();
|
||||
|
||||
SyncEngine engine=SyncEngine.get();
|
||||
engine.forceUnlock(folder.getId());
|
||||
engine.unsetSynchronizedFolder(folder.getId(), false);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,62 @@
|
||||
package org.gcube.usecases.ws.thredds;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.MalformedURLException;
|
||||
import java.util.Collections;
|
||||
|
||||
import org.gcube.common.authorization.library.provider.SecurityTokenProvider;
|
||||
import org.gcube.common.homelibrary.home.exceptions.HomeNotFoundException;
|
||||
import org.gcube.common.homelibrary.home.exceptions.InternalErrorException;
|
||||
import org.gcube.common.homelibrary.home.exceptions.UserNotFoundException;
|
||||
import org.gcube.common.homelibrary.home.workspace.WorkspaceFolder;
|
||||
import org.gcube.common.homelibrary.home.workspace.exceptions.InsufficientPrivilegesException;
|
||||
import org.gcube.common.homelibrary.home.workspace.exceptions.ItemAlreadyExistException;
|
||||
import org.gcube.common.homelibrary.home.workspace.exceptions.ItemNotFoundException;
|
||||
import org.gcube.common.homelibrary.home.workspace.exceptions.WorkspaceFolderNotFoundException;
|
||||
import org.gcube.usecases.ws.thredds.engine.impl.WorkspaceFolderManager;
|
||||
import org.gcube.usecases.ws.thredds.faults.InternalException;
|
||||
import org.gcube.usecases.ws.thredds.faults.WorkspaceInteractionException;
|
||||
import org.gcube.usecases.ws.thredds.faults.WorkspaceNotSynchedException;
|
||||
import org.gcube.usecases.ws.thredds.model.SynchFolderConfiguration;
|
||||
|
||||
public class WorkspaceLock {
|
||||
|
||||
public static void main(String[] args) throws WorkspaceFolderNotFoundException, ItemNotFoundException, InsufficientPrivilegesException, ItemAlreadyExistException, InternalErrorException, HomeNotFoundException, UserNotFoundException, WorkspaceInteractionException, InternalException, MalformedURLException, IOException {
|
||||
TestCommons.setScope();
|
||||
WorkspaceFolder folder=TestCommons.getTestFolder();
|
||||
WorkspaceFolderManager manager=new WorkspaceFolderManager(folder.getId());
|
||||
|
||||
String processID="mytest";
|
||||
try {
|
||||
System.out.println("Trying to cleanup, first.. ");
|
||||
folder.getProperties().addProperties(Collections.singletonMap(org.gcube.usecases.ws.thredds.Constants.WorkspaceProperties.TBS, null));
|
||||
System.out.println("FOLDER PROPERTIES : "+folder.getProperties().getProperties());
|
||||
}catch(Throwable t) {
|
||||
System.err.println("Dismiss error : ");
|
||||
t.printStackTrace();
|
||||
}
|
||||
|
||||
|
||||
|
||||
// manager.configure(new SynchFolderConfiguration("mySynchedCatalog","*.nc,*.ncml,*.asc",SecurityTokenProvider.instance.get()));
|
||||
|
||||
System.out.println("Is locked : "+manager.isLocked());
|
||||
System.out.println("locking ... ");
|
||||
manager.lock(processID);
|
||||
|
||||
try {
|
||||
manager.dismiss(false);
|
||||
System.err.println("It should have raised locked exception");
|
||||
}catch(Exception e){
|
||||
System.out.println("Ok check lock on dismiss ");
|
||||
}
|
||||
|
||||
manager.unlock(processID);
|
||||
|
||||
manager.dismiss(false);
|
||||
|
||||
|
||||
System.out.println("This should be false : "+manager.isSynched());
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,93 @@
|
||||
package org.gcube.usecases.ws.thredds;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.MalformedURLException;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import org.gcube.common.homelibrary.home.exceptions.HomeNotFoundException;
|
||||
import org.gcube.common.homelibrary.home.exceptions.InternalErrorException;
|
||||
import org.gcube.common.homelibrary.home.exceptions.UserNotFoundException;
|
||||
import org.gcube.common.homelibrary.home.workspace.Properties;
|
||||
import org.gcube.common.homelibrary.home.workspace.WorkspaceFolder;
|
||||
import org.gcube.common.homelibrary.home.workspace.WorkspaceItem;
|
||||
import org.gcube.common.homelibrary.home.workspace.exceptions.InsufficientPrivilegesException;
|
||||
import org.gcube.common.homelibrary.home.workspace.exceptions.ItemAlreadyExistException;
|
||||
import org.gcube.common.homelibrary.home.workspace.exceptions.ItemNotFoundException;
|
||||
import org.gcube.common.homelibrary.home.workspace.exceptions.WorkspaceFolderNotFoundException;
|
||||
import org.gcube.usecases.ws.thredds.faults.InternalException;
|
||||
import org.gcube.usecases.ws.thredds.faults.WorkspaceInteractionException;
|
||||
import org.gcube.usecases.ws.thredds.model.SynchFolderConfiguration;
|
||||
|
||||
public class WorkspaceProperties {
|
||||
|
||||
public static void main(String[] args) throws WorkspaceFolderNotFoundException, InternalErrorException, HomeNotFoundException, UserNotFoundException, InsufficientPrivilegesException, ItemAlreadyExistException, ItemNotFoundException, MalformedURLException, IOException, WorkspaceInteractionException, InternalException {
|
||||
|
||||
TestCommons.setScope();
|
||||
WorkspaceFolder folder=TestCommons.getTestFolder();
|
||||
|
||||
|
||||
SyncEngine.get().check(folder.getId(), true);
|
||||
scanForPrint(folder);
|
||||
|
||||
// SyncEngine.get().shutDown();
|
||||
// for(Workspace)
|
||||
// printProperties(folder.getProperties());
|
||||
//
|
||||
// System.out.println("Has property : "+folder.getProperties().hasProperty(org.gcube.usecases.ws.thredds.Constants.WorkspaceProperties.TBS));
|
||||
// printProperties(folder.getProperties());
|
||||
//
|
||||
//
|
||||
// System.out.println("Setting property.. ");
|
||||
// folder.getProperties().addProperties(Collections.singletonMap(org.gcube.usecases.ws.thredds.Constants.WorkspaceProperties.TBS, "true"));
|
||||
//
|
||||
// System.out.println("Has property : "+folder.getProperties().hasProperty(org.gcube.usecases.ws.thredds.Constants.WorkspaceProperties.TBS));
|
||||
// printProperties(folder.getProperties());
|
||||
//
|
||||
//
|
||||
// System.out.println("Removing (setting it null) ");
|
||||
// folder.getProperties().addProperties(Collections.singletonMap(org.gcube.usecases.ws.thredds.Constants.WorkspaceProperties.TBS, null));
|
||||
//
|
||||
// System.out.println("Has property : "+folder.getProperties().hasProperty(org.gcube.usecases.ws.thredds.Constants.WorkspaceProperties.TBS));
|
||||
// printProperties(folder.getProperties());
|
||||
//
|
||||
// String folderId=
|
||||
//
|
||||
// WorkspaceFolderManager manager=new WorkspaceFolderManager(folderId);
|
||||
//
|
||||
// manager.configure(new SynchFolderConfiguration("myRemoteFolder","thredds","*.nc,*.ncml,*.asc"));
|
||||
//
|
||||
// manager.dismiss(false);
|
||||
|
||||
}
|
||||
|
||||
public static void scanForPrint(WorkspaceFolder folder) throws InternalErrorException {
|
||||
System.out.println("Folder "+folder.getPath());
|
||||
printProperties(folder.getProperties());
|
||||
SynchFolderConfiguration config=new SynchFolderConfiguration("", "", "", "","");
|
||||
for(WorkspaceItem item:folder.getChildren())
|
||||
if(!item.isFolder()&&config.matchesFilter(item.getName())) {
|
||||
System.out.println("ITEM "+item.getPath());
|
||||
printProperties(item.getProperties());
|
||||
}
|
||||
for(WorkspaceItem item:folder.getChildren())
|
||||
if(item.isFolder())scanForPrint((WorkspaceFolder) item);
|
||||
}
|
||||
|
||||
|
||||
public static void printProperties(Properties prop) throws InternalErrorException {
|
||||
Map<String,String> map=prop.getProperties();
|
||||
System.out.print("Properties : ..");
|
||||
for(Entry<String,String> entry:map.entrySet()) {
|
||||
// if(entry.getKey().equals(Constants.WorkspaceProperties.SYNCHRONIZATION_STATUS)||
|
||||
// entry.getKey().equals(Constants.WorkspaceProperties.LAST_UPDATE_STATUS)||
|
||||
// entry.getKey().equals(Constants.WorkspaceProperties.LAST_UPDATE_TIME)) {
|
||||
if(true) {
|
||||
if(entry.getValue()==null) System.out.print(entry.getKey()+" is null;");
|
||||
else System.out.print(entry.getKey()+" = "+entry.getValue()+";");
|
||||
}
|
||||
}
|
||||
System.out.println();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,104 @@
|
||||
package org.gcube.usecases.ws.thredds;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.MalformedURLException;
|
||||
import java.util.concurrent.Semaphore;
|
||||
|
||||
import org.gcube.common.homelibrary.home.exceptions.HomeNotFoundException;
|
||||
import org.gcube.common.homelibrary.home.exceptions.InternalErrorException;
|
||||
import org.gcube.common.homelibrary.home.exceptions.UserNotFoundException;
|
||||
import org.gcube.common.homelibrary.home.workspace.WorkspaceFolder;
|
||||
import org.gcube.common.homelibrary.home.workspace.WorkspaceItem;
|
||||
import org.gcube.common.homelibrary.home.workspace.exceptions.InsufficientPrivilegesException;
|
||||
import org.gcube.common.homelibrary.home.workspace.exceptions.ItemAlreadyExistException;
|
||||
import org.gcube.common.homelibrary.home.workspace.exceptions.ItemNotFoundException;
|
||||
import org.gcube.common.homelibrary.home.workspace.exceptions.WorkspaceFolderNotFoundException;
|
||||
import org.gcube.usecases.ws.thredds.engine.impl.ProcessDescriptor;
|
||||
import org.gcube.usecases.ws.thredds.engine.impl.ProcessStatus;
|
||||
import org.gcube.usecases.ws.thredds.faults.InternalException;
|
||||
import org.gcube.usecases.ws.thredds.faults.ProcessNotFoundException;
|
||||
import org.gcube.usecases.ws.thredds.faults.WorkspaceInteractionException;
|
||||
import org.gcube.usecases.ws.thredds.faults.WorkspaceLockedException;
|
||||
import org.gcube.usecases.ws.thredds.faults.WorkspaceNotSynchedException;
|
||||
import org.gcube.usecases.ws.thredds.model.SyncOperationCallBack;
|
||||
import org.gcube.usecases.ws.thredds.model.SynchFolderConfiguration;
|
||||
|
||||
public class WorkspaceSynchronizationTest {
|
||||
|
||||
public static void main(String[] args) throws ProcessNotFoundException, InternalErrorException, WorkspaceInteractionException, InternalException, WorkspaceFolderNotFoundException, ItemNotFoundException, InsufficientPrivilegesException, ItemAlreadyExistException, HomeNotFoundException, UserNotFoundException, MalformedURLException, IOException {
|
||||
|
||||
// GET ENGINE : SINGLETON INSTANCE
|
||||
SyncEngine engine=SyncEngine.get();
|
||||
engine.setRequestLogger("requests.txt");
|
||||
|
||||
//TEST INFO...
|
||||
TestCommons.setScope();
|
||||
WorkspaceFolder folder=TestCommons.getTestFolder();
|
||||
|
||||
// FOLDER CONFIGURATION BEAN
|
||||
SynchFolderConfiguration config=TestCommons.getSynchConfig();
|
||||
|
||||
// try {
|
||||
// //try to clean it up, first..
|
||||
// System.out.println("Cleaning it up..");
|
||||
// engine.unsetSynchronizedFolder(folder.getId(), false);
|
||||
// }catch(WorkspaceNotSynchedException e) {
|
||||
// // it was already cleared
|
||||
// }catch(WorkspaceLockedException e) {
|
||||
// engine.forceUnlock(folder.getId());
|
||||
// engine.unsetSynchronizedFolder(folder.getId(), false);
|
||||
// }
|
||||
|
||||
|
||||
|
||||
|
||||
try {
|
||||
// WHEN OPENING A FOLDER, INVOKE CHECK TO UPDATE SYNCH STATUS
|
||||
engine.check(folder.getId(), false);
|
||||
}catch(WorkspaceNotSynchedException e) {
|
||||
System.out.println("Folder not synched, configurin it..");
|
||||
engine.setSynchronizedFolder(config, folder.getId());
|
||||
engine.check(folder.getId(), false);
|
||||
}catch(WorkspaceLockedException e) {
|
||||
System.out.println("Workspace locked, going to force unlock.."); // MAINLY FOR TEST PURPOSES, OR WHEN SOMETHIGN GOES WRONG.. USE CAUTIOUSLY
|
||||
engine.forceUnlock(folder.getId());
|
||||
engine.check(folder.getId(), false);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// INVOKE SYNCHRONIZATION ON FOLDER
|
||||
ProcessDescriptor descriptor=engine.doSync(folder.getId());
|
||||
|
||||
System.out.println("Obtained descriptor : "+descriptor);
|
||||
|
||||
Semaphore sem=new Semaphore(0);
|
||||
|
||||
// REGISTER CALLBACK TO MONITOR PROGRESS
|
||||
engine.registerCallBack(folder.getId(), new SyncOperationCallBack() {
|
||||
|
||||
@Override
|
||||
public void onStep(ProcessStatus status, ProcessDescriptor descriptor) {
|
||||
System.out.println("ON STEP : "+status+" "+descriptor);
|
||||
System.out.println("LOG : \n"+ status.getLogBuilder().toString());
|
||||
if(status.getStatus().equals(ProcessStatus.Status.COMPLETED)) sem.release();
|
||||
}
|
||||
});
|
||||
|
||||
System.out.println("Waiting for process.. ");
|
||||
try {
|
||||
sem.acquire();
|
||||
} catch (InterruptedException e) {
|
||||
|
||||
}
|
||||
|
||||
engine.check(folder.getId(), true);
|
||||
|
||||
|
||||
// INVOKE WHEN PORTAL SHUTS DOWN TO FREE RESOURCES AND STOP SYNC PROCESSES
|
||||
engine.shutDown();
|
||||
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue