diff --git a/modules/AdministrationGUI/pom.xml b/modules/AdministrationGUI/pom.xml
index 3f739f5166..e8ab0f0484 100644
--- a/modules/AdministrationGUI/pom.xml
+++ b/modules/AdministrationGUI/pom.xml
@@ -5,14 +5,14 @@
org.janelia
workstation
- 9.20.1
+ 9.21.RC4
../..
AdministrationGUI
org.janelia.workstation
adminstration
- 9.20.1
+ 9.21.RC4
nbm
diff --git a/modules/ColorDepthSearch/pom.xml b/modules/ColorDepthSearch/pom.xml
index 8e1ad558f0..f5f5823aa3 100644
--- a/modules/ColorDepthSearch/pom.xml
+++ b/modules/ColorDepthSearch/pom.xml
@@ -5,14 +5,14 @@
org.janelia
workstation
- 9.20.1
+ 9.21.RC4
../..
ColorDepthSearch
org.janelia.workstation
colordepth
- 9.20.1
+ 9.21.RC4
nbm
diff --git a/modules/CommonGUI/pom.xml b/modules/CommonGUI/pom.xml
index 4fa2d4f1b3..33a6fef786 100644
--- a/modules/CommonGUI/pom.xml
+++ b/modules/CommonGUI/pom.xml
@@ -5,14 +5,14 @@
org.janelia
workstation
- 9.20.1
+ 9.21.RC4
../..
CommonGUI
org.janelia.workstation
common-gui
- 9.20.1
+ 9.21.RC4
nbm
diff --git a/modules/CommonLibraries/pom.xml b/modules/CommonLibraries/pom.xml
index bcd3ee32fe..00d8e32125 100644
--- a/modules/CommonLibraries/pom.xml
+++ b/modules/CommonLibraries/pom.xml
@@ -5,14 +5,14 @@
org.janelia
workstation
- 9.20.1
+ 9.21.RC4
../..
CommonLibraries
org.janelia.workstation
libraries
- 9.20.1
+ 9.21.RC4
nbm
@@ -53,14 +53,6 @@
org.janelia.jacs-model
jacs-model-rendering
-
- org.janelia.jacs-storage
- jacsstorage-api
-
-
- org.janelia.jacs-storage
- jacsstorage-core
-
org.janelia.jacs-storage
jacsstorage-clients
@@ -776,6 +768,9 @@
org.janelia.rendering
org.janelia.rendering.utils
org.janelia.rendering.ymlrepr
+ org.janelia.jacsstorage.clients.api
+ org.janelia.jacsstorage.clients.api.http
+ org.janelia.jacsstorage.clients.api.rendering
org.jdesktop.swingx.*
org.jnp.*
org.perf4j
diff --git a/modules/Core/pom.xml b/modules/Core/pom.xml
index 1ac02f82a4..275b9ef5bf 100644
--- a/modules/Core/pom.xml
+++ b/modules/Core/pom.xml
@@ -5,14 +5,14 @@
org.janelia
workstation
- 9.20.1
+ 9.21.RC4
../..
Core
org.janelia.workstation
core
- 9.20.1
+ 9.21.RC4
nbm
diff --git a/modules/Core/src/main/java/org/janelia/workstation/core/api/facade/impl/rest/AsyncServiceFacadeImpl.java b/modules/Core/src/main/java/org/janelia/workstation/core/api/facade/impl/rest/AsyncServiceFacadeImpl.java
index cb10d58dd5..ef933b0432 100644
--- a/modules/Core/src/main/java/org/janelia/workstation/core/api/facade/impl/rest/AsyncServiceFacadeImpl.java
+++ b/modules/Core/src/main/java/org/janelia/workstation/core/api/facade/impl/rest/AsyncServiceFacadeImpl.java
@@ -36,7 +36,10 @@ public AsyncServiceMonitoringWorker executeColorDepthService(ColorDepthSearch se
// Invoke the service
ActivityLogHelper.logUserAction("AsyncServiceFacadeImpl.executeColorDepthService", search);
Long serviceId = asyncServiceClient.invokeService("colorDepthObjectSearch",
- args, DEFAULT_PROCESSING_LOCATION, ImmutableMap.of());
+ args, DEFAULT_PROCESSING_LOCATION,
+ ImmutableMap.of(),
+ ImmutableMap.of() // invocation headers
+ );
// Create a monitoring worker
AsyncServiceMonitoringWorker executeWorker = new SearchMonitoringWorker(search, serviceId);
diff --git a/modules/Core/src/main/java/org/janelia/workstation/core/api/facade/impl/rest/DomainFacadeImpl.java b/modules/Core/src/main/java/org/janelia/workstation/core/api/facade/impl/rest/DomainFacadeImpl.java
index 4fac32d121..02e99c2196 100644
--- a/modules/Core/src/main/java/org/janelia/workstation/core/api/facade/impl/rest/DomainFacadeImpl.java
+++ b/modules/Core/src/main/java/org/janelia/workstation/core/api/facade/impl/rest/DomainFacadeImpl.java
@@ -208,7 +208,7 @@ public void removeObjectStorage(List storagePaths) {
WebTarget storageService = RestJsonClientManager.getInstance().getTarget(remoteStorageUrl, true);
for (String storagePath : storagePaths) {
WebTarget target = storageService.path("storage_content/storage_path_redirect")
- .path(storagePath);
+ .queryParam("contentPath", storagePath);
Response response = target
.request("application/json")
.delete();
diff --git a/modules/Core/src/main/java/org/janelia/workstation/core/api/http/RestJsonClientManager.java b/modules/Core/src/main/java/org/janelia/workstation/core/api/http/RestJsonClientManager.java
index 43a86804ec..0497fed396 100644
--- a/modules/Core/src/main/java/org/janelia/workstation/core/api/http/RestJsonClientManager.java
+++ b/modules/Core/src/main/java/org/janelia/workstation/core/api/http/RestJsonClientManager.java
@@ -95,9 +95,11 @@ public boolean handleUnknownProperty(DeserializationContext ctxt, JsonParser jp,
return;
}
+ log.info("Redirect to {}", clientResponseContext.getLocation());
try (Response resp = clientRequestContext.getClient()
.target(clientResponseContext.getLocation())
.request()
+ .headers(clientRequestContext.getHeaders())
.method(clientRequestContext.getMethod())) {
clientResponseContext.setEntityStream((InputStream) resp.getEntity());
clientResponseContext.setStatusInfo(resp.getStatusInfo());
diff --git a/modules/Core/src/main/java/org/janelia/workstation/core/api/web/AsyncServiceClient.java b/modules/Core/src/main/java/org/janelia/workstation/core/api/web/AsyncServiceClient.java
index d636324484..841f6985c7 100644
--- a/modules/Core/src/main/java/org/janelia/workstation/core/api/web/AsyncServiceClient.java
+++ b/modules/Core/src/main/java/org/janelia/workstation/core/api/web/AsyncServiceClient.java
@@ -7,6 +7,7 @@
import java.util.Map;
import javax.ws.rs.client.Entity;
+import javax.ws.rs.client.Invocation;
import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.Response;
@@ -45,7 +46,8 @@ public AsyncServiceClient(String serverUrl) {
public Long invokeService(String serviceName,
List serviceArgs,
String processingLocation,
- Map serviceResources) throws ServiceException {
+ Map serviceResources,
+ Map invocationHeaders) throws ServiceException {
AsyncServiceData body = new AsyncServiceData();
if (serviceArgs != null) {
body.args.addAll(serviceArgs);
@@ -57,9 +59,12 @@ public Long invokeService(String serviceName,
body.processingLocation = processingLocation;
}
WebTarget target = service.path("async-services").path(serviceName);
- Response response = target
- .request("application/json")
- .post(Entity.json(body));
+ Invocation.Builder requestInvocation = target
+ .request("application/json");
+ for (Map.Entry entry : invocationHeaders.entrySet()) {
+ requestInvocation = requestInvocation.header(entry.getKey(), String.valueOf(entry.getValue()));
+ }
+ Response response = requestInvocation.post(Entity.json(body));
if (response.getStatus() != 201) {
throw new ServiceException("Service " + serviceName + " returned status "+response.getStatus());
}
diff --git a/modules/Core/src/main/java/org/janelia/workstation/core/api/web/JadeServiceClient.java b/modules/Core/src/main/java/org/janelia/workstation/core/api/web/JadeServiceClient.java
index 28bb9d5dc6..a332a95c02 100644
--- a/modules/Core/src/main/java/org/janelia/workstation/core/api/web/JadeServiceClient.java
+++ b/modules/Core/src/main/java/org/janelia/workstation/core/api/web/JadeServiceClient.java
@@ -1,28 +1,24 @@
package org.janelia.workstation.core.api.web;
import java.io.InputStream;
-import java.net.URI;
-import java.net.URISyntaxException;
import java.nio.file.Paths;
-import java.util.List;
import java.util.Optional;
+import javax.ws.rs.client.Client;
+import javax.ws.rs.client.Invocation;
import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.GenericType;
import javax.ws.rs.core.Response;
-import javax.ws.rs.core.UriBuilder;
-import com.fasterxml.jackson.annotation.JsonAutoDetect;
-import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
-import com.fasterxml.jackson.annotation.JsonProperty;
import com.google.common.base.Preconditions;
-
import org.apache.commons.lang3.RegExUtils;
import org.apache.commons.lang3.StringUtils;
-import org.janelia.rendering.JADEBasedDataLocation;
+import org.janelia.jacsstorage.clients.api.JadeResults;
+import org.janelia.jacsstorage.clients.api.JadeStorageAttributes;
+import org.janelia.jacsstorage.clients.api.JadeStorageVolume;
+import org.janelia.jacsstorage.clients.api.http.HttpClientProvider;
+import org.janelia.jacsstorage.clients.api.rendering.JadeBasedDataLocation;
import org.janelia.rendering.Streamable;
-import org.janelia.rendering.utils.ClientProxy;
-import org.janelia.rendering.utils.HttpClientProvider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -33,54 +29,18 @@ public class JadeServiceClient {
private static final Logger LOG = LoggerFactory.getLogger(JadeServiceClient.class);
- @JsonIgnoreProperties(ignoreUnknown = true)
- @JsonAutoDetect(
- fieldVisibility = JsonAutoDetect.Visibility.ANY,
- setterVisibility = JsonAutoDetect.Visibility.NONE
- )
- private static class JadeResults {
- @JsonProperty
- @SuppressWarnings("MismatchedQueryAndUpdateOfCollection")
- private List resultList;
- }
-
- @JsonIgnoreProperties(ignoreUnknown = true)
- @JsonAutoDetect(
- fieldVisibility = JsonAutoDetect.Visibility.ANY,
- setterVisibility = JsonAutoDetect.Visibility.NONE
- )
- private static class JadeStorageVolume {
- @JsonProperty
- private String id;
- @JsonProperty
- private String storageServiceURL;
- @JsonProperty
- private String baseStorageRootDir;
- @JsonProperty
- private String storageVirtualPath;
-
- String getVolumeStorageURI() {
- try {
- return UriBuilder.fromUri(new URI(storageServiceURL)).path("agent_storage/storage_volume").path(id).build().toString();
- } catch (URISyntaxException e) {
- throw new IllegalArgumentException(e);
- }
- }
-
- }
-
private final String jadeURL; // jade master node URL
- private final HttpClientProvider httpClientProvider;
+ private final HttpClientProvider clientProvider;
- public JadeServiceClient(String jadeURL, HttpClientProvider httpClientProvider) {
+ public JadeServiceClient(String jadeURL, HttpClientProvider clientProvider) {
Preconditions.checkArgument(StringUtils.isNotBlank(jadeURL));
this.jadeURL = jadeURL;
- this.httpClientProvider = httpClientProvider;
+ this.clientProvider = clientProvider;
}
public Optional findStorageURL(String storagePath) {
Preconditions.checkArgument(storagePath != null && storagePath.trim().length() > 0);
- ClientProxy httpClient = getHttpClient();
+ Client httpClient = clientProvider.getClient();
try {
LOG.debug("Lookup storage for {}", storagePath);
WebTarget target = httpClient.target(jadeURL)
@@ -95,23 +55,22 @@ public Optional findStorageURL(String storagePath) {
}
JadeResults storageContentResults = response.readEntity(new GenericType>() {
});
- return storageContentResults.resultList.stream().findFirst().map(jadeVolume -> jadeVolume.storageServiceURL);
+ return storageContentResults.getResultList().stream().findFirst().map(JadeStorageVolume::getStorageServiceURL);
} finally {
httpClient.close();
}
}
- public Optional findDataLocation(String storagePathParam) {
+ public Optional findDataLocation(String storagePathParam, JadeStorageAttributes storageAttributes) {
Preconditions.checkArgument(storagePathParam != null && storagePathParam.trim().length() > 0);
String storagePath = RegExUtils.replaceFirst(StringUtils.replaceChars(storagePathParam, '\\', '/'), "^((.+:)?/+)+", "/");
- ClientProxy httpClient = getHttpClient();
+ Client httpClient = clientProvider.getClient();
try {
LOG.debug("Lookup storage for {}", storagePath);
WebTarget target = httpClient.target(jadeURL)
.path("storage_volumes")
.queryParam("dataStoragePath", storagePath);
- Response response = target.request()
- .get();
+ Response response = createRequest(target, storageAttributes).get();
int responseStatus = response.getStatus();
if (responseStatus != Response.Status.OK.getStatusCode()) {
LOG.error("Request to {} returned with status {}", target, responseStatus);
@@ -119,22 +78,22 @@ public Optional findDataLocation(String storagePathParam)
}
JadeResults storageContentResults = response.readEntity(new GenericType>() {
});
- return storageContentResults.resultList.stream().findFirst()
+ return storageContentResults.getResultList().stream().findFirst()
.map(jadeVolume -> {
String renderedVolumePath;
- if (storagePath.startsWith(jadeVolume.storageVirtualPath)) {
- renderedVolumePath = Paths.get(jadeVolume.storageVirtualPath).relativize(Paths.get(storagePath)).toString();
+ if (StringUtils.startsWith(storagePath, jadeVolume.getStorageVirtualPath())) {
+ renderedVolumePath = Paths.get(jadeVolume.getStorageVirtualPath()).relativize(Paths.get(storagePath)).toString();
} else {
- renderedVolumePath = Paths.get(jadeVolume.baseStorageRootDir).relativize(Paths.get(storagePath)).toString();
+ renderedVolumePath = Paths.get(jadeVolume.getBaseStorageRootDir()).relativize(Paths.get(storagePath)).toString();
}
- LOG.info("Create JADE volume location with URLs {}, {} and volume path {}", jadeVolume.storageServiceURL, jadeVolume.getVolumeStorageURI(), renderedVolumePath);
- return new JADEBasedDataLocation(
- jadeVolume.storageServiceURL,
+ LOG.info("Create JADE volume location with URLs {}, {} and volume path {}", jadeVolume.getStorageServiceURL(), jadeVolume.getVolumeStorageURI(), renderedVolumePath);
+ return new JadeBasedDataLocation(
+ jadeVolume.getStorageServiceURL(),
jadeVolume.getVolumeStorageURI(),
renderedVolumePath,
null,
null,
- httpClientProvider);
+ storageAttributes);
})
;
} finally {
@@ -143,17 +102,16 @@ public Optional findDataLocation(String storagePathParam)
}
- public Streamable streamContent(String serverURL, String dataPath) {
+ public Streamable streamContent(String serverURL, String dataPath, JadeStorageAttributes storageAttributes) {
Preconditions.checkArgument(serverURL != null && serverURL.trim().length() > 0);
Preconditions.checkArgument(dataPath != null && dataPath.trim().length() > 0);
- ClientProxy httpClient = getHttpClient();
+ Client httpClient = clientProvider.getClient();
try {
WebTarget target = httpClient.target(serverURL)
.path("agent_storage/storage_path/data_content")
.path(dataPath);
LOG.info("Streaming tile from {}", target);
- Response response = target.request()
- .get();
+ Response response = createRequest(target, storageAttributes).get();
int responseStatus = response.getStatus();
if (responseStatus == Response.Status.OK.getStatusCode()) {
InputStream is = (InputStream) response.getEntity();
@@ -167,16 +125,15 @@ public Streamable streamContent(String serverURL, String dataPath)
}
}
- public boolean checkStoragePath(String storagePath) {
+ public boolean checkStoragePath(String storagePath, JadeStorageAttributes storageAttributes) {
Preconditions.checkArgument(storagePath != null && storagePath.trim().length() > 0);
- ClientProxy httpClient = getHttpClient();
+ Client httpClient = clientProvider.getClient();
try {
LOG.debug("Check if storage path exists {}", storagePath);
WebTarget target = httpClient.target(jadeURL)
.path("storage_content/storage_path_redirect")
- .path(storagePath);
- Response response = target.request()
- .head();
+ .queryParam("contentPath", storagePath);
+ Response response = createRequest(target, storageAttributes).head();
int responseStatus = response.getStatus();
if (responseStatus != Response.Status.OK.getStatusCode()) {
LOG.error("Request to {} returned with status {}", target, responseStatus);
@@ -189,8 +146,14 @@ public boolean checkStoragePath(String storagePath) {
}
}
- private ClientProxy getHttpClient() {
- return httpClientProvider.getClient();
+ private Invocation.Builder createRequest(WebTarget target, JadeStorageAttributes storageAttributes) {
+ Invocation.Builder requestBuilder = target.request();
+ for (String storageAttribute : storageAttributes.getAttributeNames()) {
+ requestBuilder = requestBuilder.header(
+ storageAttribute,
+ storageAttributes.getAttributeValue(storageAttribute)
+ );
+ }
+ return requestBuilder;
}
-
}
diff --git a/modules/Core/src/main/java/org/janelia/workstation/core/filecache/MasterStorageClient.java b/modules/Core/src/main/java/org/janelia/workstation/core/filecache/MasterStorageClient.java
index b99f8ab5e3..ecceb41aba 100644
--- a/modules/Core/src/main/java/org/janelia/workstation/core/filecache/MasterStorageClient.java
+++ b/modules/Core/src/main/java/org/janelia/workstation/core/filecache/MasterStorageClient.java
@@ -58,11 +58,11 @@ WebDavStorage findStorage(String storagePath) throws WebDavException, FileNotFou
}
String createStorage(String storageName, String storageContext, String storageTags) {
- return createStorageForResource(getCreateStorageURL(storageName, "DATA_DIRECTORY"), storageContext, storageTags);
- }
-
- private String getCreateStorageURL(String storageName, String storageType) {
- return baseUrl + "/storage/" + storageName + "/format/" + storageType;
+ return createStorageForResource(
+ baseUrl + "/storage/" + storageName + "/format/DATA_DIRECTORY",
+ storageContext,
+ storageTags
+ );
}
private String createStorageForResource(String resourceURI, String storageContext, String storageTags) {
diff --git a/modules/Core/src/main/java/org/janelia/workstation/core/filecache/StorageClientResponseHelper.java b/modules/Core/src/main/java/org/janelia/workstation/core/filecache/StorageClientResponseHelper.java
index fb452bd6e3..5a062ae1bb 100644
--- a/modules/Core/src/main/java/org/janelia/workstation/core/filecache/StorageClientResponseHelper.java
+++ b/modules/Core/src/main/java/org/janelia/workstation/core/filecache/StorageClientResponseHelper.java
@@ -30,8 +30,7 @@ static MultiStatusResponse[] getResponses(HttpClientProxy httpClient, String hre
if (responseCode == HttpStatus.SC_MULTI_STATUS) {
final MultiStatus multiStatus = method.getResponseBodyAsMultiStatus();
multiStatusResponses = multiStatus.getResponses();
- }
- else if (responseCode == HttpStatus.SC_MOVED_PERMANENTLY) {
+ } else if (responseCode == HttpStatus.SC_MOVED_PERMANENTLY) {
final Header locationHeader = method.getResponseHeader("Location");
if (locationHeader != null) {
final String movedHref = locationHeader.getValue();
@@ -40,12 +39,10 @@ else if (responseCode == HttpStatus.SC_MOVED_PERMANENTLY) {
}
}
throw new WebDavException(responseCode + " response code returned for " + href, responseCode);
- }
- else if (responseCode == HttpStatus.SC_NOT_FOUND) {
+ } else if (responseCode == HttpStatus.SC_NOT_FOUND) {
LOG.debug("File not found: {}", href);
throw new FileNotFoundException("Resource " + href + " not found (" + responseCode + ")");
- }
- else {
+ } else {
throw new WebDavException(responseCode + " response code returned for " + href, responseCode);
}
}
@@ -71,7 +68,7 @@ static String getStorageLookupURL(String baseUrl, String context, String remoteF
return null;
}
else {
- return baseUrl + "/" + context + "/" + remoteFileName;
+ return baseUrl + "/" + context + "?contentPath=" + remoteFileName;
}
}
diff --git a/modules/Core/src/main/java/org/janelia/workstation/core/util/SystemInfo.java b/modules/Core/src/main/java/org/janelia/workstation/core/util/SystemInfo.java
index 3e79b5eb35..748b730082 100644
--- a/modules/Core/src/main/java/org/janelia/workstation/core/util/SystemInfo.java
+++ b/modules/Core/src/main/java/org/janelia/workstation/core/util/SystemInfo.java
@@ -59,14 +59,14 @@ public class SystemInfo {
public static final boolean isMacIntel64 = isMac && "x86_64".equals(OS_ARCH);
- public static final String nativeFileManagerName = isMac ? "Finder" : isGnome ? "Nautilus" : isKDE ? "Konqueror" : "Explorer";
-
public static final String optionsMenuName = isMac ? "Preferences" : "Tools->Options";
public static final String appName = ConsoleProperties.getString("client.Title");
public static final String appVersion = ConsoleProperties.getString("client.versionNumber");
- public static final boolean isDev = "DEV".equals(appVersion);
+ public static final boolean isDev = "DEV".equals(appVersion)
+ || appVersion.contains("SNAPSHOT")
+ || appVersion.contains("RC");
public static final boolean isTest = "TEST".equals(appVersion);
/**
diff --git a/modules/Core/src/test/java/org/janelia/workstation/core/filecache/AgentStorageClientTest.java b/modules/Core/src/test/java/org/janelia/workstation/core/filecache/AgentStorageClientTest.java
index 78bfd46219..9f7e323e62 100644
--- a/modules/Core/src/test/java/org/janelia/workstation/core/filecache/AgentStorageClientTest.java
+++ b/modules/Core/src/test/java/org/janelia/workstation/core/filecache/AgentStorageClientTest.java
@@ -52,7 +52,7 @@ public void findFile() throws Exception {
String fileName = "/p1/p2/p3";
PropFindMethod testMethod = Mockito.mock(PropFindMethod.class);
- PowerMockito.whenNew(PropFindMethod.class).withArguments(BASE_WEBDAV_URL + "/data_storage_path/" + fileName, WebDavFile.PROPERTY_NAMES, 0).thenReturn(testMethod);
+ PowerMockito.whenNew(PropFindMethod.class).withArguments(BASE_WEBDAV_URL + "/data_storage_path?contentPath=" + fileName, WebDavFile.PROPERTY_NAMES, 0).thenReturn(testMethod);
Mockito.when(httpClient.executeMethod(testMethod)).thenReturn(207);
String returnedUrl = "http://test";
diff --git a/modules/Core/src/test/java/org/janelia/workstation/core/filecache/MasterStorageClientTest.java b/modules/Core/src/test/java/org/janelia/workstation/core/filecache/MasterStorageClientTest.java
index 883b9606f9..d64fe56267 100644
--- a/modules/Core/src/test/java/org/janelia/workstation/core/filecache/MasterStorageClientTest.java
+++ b/modules/Core/src/test/java/org/janelia/workstation/core/filecache/MasterStorageClientTest.java
@@ -51,7 +51,7 @@ public void findStorage() throws Exception {
String storagePrefix = "/p1/p2";
PropFindMethod testMethod = Mockito.mock(PropFindMethod.class);
- PowerMockito.whenNew(PropFindMethod.class).withArguments(BASE_WEBDAV_URL + "/data_storage_path/" + storagePrefix, WebDavFile.PROPERTY_NAMES, 0)
+ PowerMockito.whenNew(PropFindMethod.class).withArguments(BASE_WEBDAV_URL + "/data_storage_path?contentPath=" + storagePrefix, WebDavFile.PROPERTY_NAMES, 0)
.thenReturn(testMethod);
Mockito.when(httpClient.executeMethod(testMethod)).thenReturn(207);
diff --git a/modules/DarculaLAF/pom.xml b/modules/DarculaLAF/pom.xml
index 042c9be41e..524ec87c84 100644
--- a/modules/DarculaLAF/pom.xml
+++ b/modules/DarculaLAF/pom.xml
@@ -5,14 +5,14 @@
org.janelia
workstation
- 9.20.1
+ 9.21.RC4
../..
DarculaLAF
org.janelia.workstation
darcula
- 9.20.1
+ 9.21.RC4
nbm
diff --git a/modules/DataBrowser/pom.xml b/modules/DataBrowser/pom.xml
index 35f3367539..34985f5f0b 100644
--- a/modules/DataBrowser/pom.xml
+++ b/modules/DataBrowser/pom.xml
@@ -5,14 +5,14 @@
org.janelia
workstation
- 9.20.1
+ 9.21.RC4
../..
DataBrowser
org.janelia.workstation
browser
- 9.20.1
+ 9.21.RC4
nbm
diff --git a/modules/DataBrowser/src/main/java/org/janelia/workstation/browser/actions/context/RefreshSyncedRootAction.java b/modules/DataBrowser/src/main/java/org/janelia/workstation/browser/actions/context/RefreshSyncedRootAction.java
index a79b8fac5c..a17a3e9edf 100644
--- a/modules/DataBrowser/src/main/java/org/janelia/workstation/browser/actions/context/RefreshSyncedRootAction.java
+++ b/modules/DataBrowser/src/main/java/org/janelia/workstation/browser/actions/context/RefreshSyncedRootAction.java
@@ -83,7 +83,8 @@ protected void doStuff() throws Exception {
Long taskId = asyncServiceClient.invokeService("syncedRoot",
serviceArgsBuilder.build(),
null,
- ImmutableMap.of()
+ ImmutableMap.of(),
+ syncedRoot.getStorageAttributes()
);
setServiceId(taskId);
diff --git a/modules/DataBrowser/src/main/java/org/janelia/workstation/browser/gui/dialogs/SyncedRootDialog.java b/modules/DataBrowser/src/main/java/org/janelia/workstation/browser/gui/dialogs/SyncedRootDialog.java
index 5ce26fbb4a..2612db0613 100644
--- a/modules/DataBrowser/src/main/java/org/janelia/workstation/browser/gui/dialogs/SyncedRootDialog.java
+++ b/modules/DataBrowser/src/main/java/org/janelia/workstation/browser/gui/dialogs/SyncedRootDialog.java
@@ -28,6 +28,10 @@
public class SyncedRootDialog extends ModalDialog {
private JTextField pathTextField;
+ private JLabel accessKeyLabel;
+ private JTextField accessKeyTextField;
+ private JLabel secretKeyLabel;
+ private JTextField secretKeyTextField;
private JTextField nameField;
private JTextField depthField;
private JPanel subjectPanel;
@@ -52,10 +56,39 @@ public SyncedRootDialog() {
attrPanel.addItem(instructions);
- this.pathTextField = new JTextField(50);
+ pathTextField = new JTextField(50);
pathTextField.setToolTipText("The filepath must be accessible to the backend JADE service");
attrPanel.addItem("Path", pathTextField);
+ JCheckBox storageCredentialsRequiredCheckbox = new JCheckBox();
+ attrPanel.addItem("Storage requires credentials", storageCredentialsRequiredCheckbox);
+
+ accessKeyTextField = new JTextField(50);
+ accessKeyTextField.setToolTipText("Access key for the provided path");
+ accessKeyLabel = attrPanel.addItem("Access Key", accessKeyTextField);
+ accessKeyLabel.setVisible(false);
+ accessKeyTextField.setVisible(false);
+
+ secretKeyTextField = new JTextField(50);
+ secretKeyTextField.setToolTipText("Secret key for the provided path");
+ secretKeyLabel = attrPanel.addItem("Secret Key", secretKeyTextField);
+ secretKeyLabel.setVisible(false);
+ secretKeyTextField.setVisible(false);
+
+ storageCredentialsRequiredCheckbox.addActionListener(e -> {
+ if (storageCredentialsRequiredCheckbox.isSelected()) {
+ accessKeyLabel.setVisible(true);
+ secretKeyLabel.setVisible(true);
+ accessKeyTextField.setVisible(true);
+ secretKeyTextField.setVisible(true);
+ } else {
+ accessKeyLabel.setVisible(false);
+ secretKeyLabel.setVisible(false);
+ accessKeyTextField.setVisible(false);
+ secretKeyTextField.setVisible(false);
+ }
+ });
+
this.nameField = new JTextField(50);
nameField.setToolTipText("Name of the Synchronized Folder in the Workstation. If blank, the filepath will be used.");
attrPanel.addItem("Name (optional)", nameField);
@@ -138,8 +171,7 @@ public void showDialog(SyncedRoot syncedRoot) {
JCheckBox checkBox = agentTypeMap.get(agentType);
checkBox.setSelected(syncedRoot.getDiscoveryAgents().contains(agentType));
}
- }
- else {
+ } else {
setTitle("Add Synchronized Folder");
subjectPanel.add(subjectCombobox);
}
@@ -190,6 +222,13 @@ private void saveAndClose(boolean sync) {
}
}
+ if (StringUtils.isNotBlank(accessKeyTextField.getText())) {
+ syncedRoot.setStorageAttribute("AccessKey", accessKeyTextField.getText().trim());
+ }
+ if (StringUtils.isNotBlank(secretKeyTextField.getText())) {
+ syncedRoot.setStorageAttribute("SecretKey", secretKeyTextField.getText().trim());
+ }
+
if (syncedRoot.getDiscoveryAgents().isEmpty()) {
JOptionPane.showMessageDialog(this, "Select one or more discovery agents", "No agents selected", JOptionPane.ERROR_MESSAGE);
return;
@@ -202,7 +241,7 @@ private void saveAndClose(boolean sync) {
setVisible(false);
}
- public static void refreshSyncedRoot(SyncedRoot root) {
+ private static void refreshSyncedRoot(SyncedRoot root) {
BackgroundWorker worker = new AsyncServiceMonitoringWorker() {
@@ -226,7 +265,8 @@ protected void doStuff() throws Exception {
Long taskId = asyncServiceClient.invokeService("syncedRoot",
serviceArgsBuilder.build(),
null,
- ImmutableMap.of()
+ ImmutableMap.of(),
+ savedRoot.getStorageAttributes()
);
setServiceId(taskId);
diff --git a/modules/GLViewerTools/pom.xml b/modules/GLViewerTools/pom.xml
index d2d2454dcc..4ecc19202d 100644
--- a/modules/GLViewerTools/pom.xml
+++ b/modules/GLViewerTools/pom.xml
@@ -5,14 +5,14 @@
org.janelia
workstation
- 9.20.1
+ 9.21.RC4
../..
GLViewerTools
org.janelia.workstation
gltools
- 9.20.1
+ 9.21.RC4
nbm
diff --git a/modules/Geometry3d/pom.xml b/modules/Geometry3d/pom.xml
index 6433a58211..2bce28f4cd 100644
--- a/modules/Geometry3d/pom.xml
+++ b/modules/Geometry3d/pom.xml
@@ -5,14 +5,14 @@
org.janelia
workstation
- 9.20.1
+ 9.21.RC4
../..
Geometry3d
org.janelia.workstation
geometry3d
- 9.20.1
+ 9.21.RC4
nbm
diff --git a/modules/HortaTracer/pom.xml b/modules/HortaTracer/pom.xml
index 8b0a31dfae..e5b02d5021 100644
--- a/modules/HortaTracer/pom.xml
+++ b/modules/HortaTracer/pom.xml
@@ -5,14 +5,14 @@
org.janelia
workstation
- 9.20.1
+ 9.21.RC4
../..
HortaTracer
org.janelia.workstation
horta
- 9.20.1
+ 9.21.RC4
nbm
diff --git a/modules/HortaTracer/src/main/java/org/janelia/horta/JadeBasedTileLoader.java b/modules/HortaTracer/src/main/java/org/janelia/horta/JadeBasedTileLoader.java
index 28bce8ac84..a50083e8bf 100644
--- a/modules/HortaTracer/src/main/java/org/janelia/horta/JadeBasedTileLoader.java
+++ b/modules/HortaTracer/src/main/java/org/janelia/horta/JadeBasedTileLoader.java
@@ -4,6 +4,7 @@
import java.io.InputStream;
import java.util.Optional;
+import org.janelia.jacsstorage.clients.api.JadeStorageAttributes;
import org.janelia.rendering.Streamable;
import org.janelia.workstation.core.api.web.JadeServiceClient;
import org.slf4j.Logger;
@@ -17,9 +18,11 @@ public class JadeBasedTileLoader implements TileLoader {
private static final Logger LOG = LoggerFactory.getLogger(JadeBasedTileLoader.class);
private final JadeServiceClient jadeClient;
+ private final JadeStorageAttributes storageAttributes;
- JadeBasedTileLoader(JadeServiceClient jadeClient) {
+ JadeBasedTileLoader(JadeServiceClient jadeClient, JadeStorageAttributes storageAttributes) {
this.jadeClient = jadeClient;
+ this.storageAttributes = storageAttributes;
}
@Override
@@ -32,7 +35,7 @@ public Streamable streamTileContent(String storageLocation, String
long startTime = System.currentTimeMillis();
try {
LOG.debug("Open stream for reading tile bytes from {} for {}", storageLocation, tileLocation);
- return jadeClient.streamContent(storageLocation, tileLocation);
+ return jadeClient.streamContent(storageLocation, tileLocation, storageAttributes);
} finally {
LOG.info("Opened content for reading tile bytes from {} for {} in {} ms",
storageLocation, tileLocation,
@@ -42,6 +45,6 @@ public Streamable streamTileContent(String storageLocation, String
@Override
public boolean checkStorageLocation(String tileLocation) {
- return jadeClient.checkStoragePath(tileLocation);
+ return jadeClient.checkStoragePath(tileLocation, storageAttributes);
}
}
diff --git a/modules/HortaTracer/src/main/java/org/janelia/horta/NeuronTracerTopComponent.java b/modules/HortaTracer/src/main/java/org/janelia/horta/NeuronTracerTopComponent.java
index 2a91ebb0b4..5760fb28fc 100644
--- a/modules/HortaTracer/src/main/java/org/janelia/horta/NeuronTracerTopComponent.java
+++ b/modules/HortaTracer/src/main/java/org/janelia/horta/NeuronTracerTopComponent.java
@@ -1,13 +1,26 @@
package org.janelia.horta;
-import java.awt.*;
-
-import org.apache.commons.lang.StringUtils;
-import org.janelia.horta.omezarr.OmeZarrReaderCompletionObserver;
-import org.janelia.model.domain.enums.FileType;
-import java.awt.datatransfer.*;
-import java.awt.dnd.*;
-import java.awt.event.*;
+import java.awt.BorderLayout;
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.FileDialog;
+import java.awt.FlowLayout;
+import java.awt.Frame;
+import java.awt.Point;
+import java.awt.Toolkit;
+import java.awt.datatransfer.Clipboard;
+import java.awt.datatransfer.DataFlavor;
+import java.awt.datatransfer.StringSelection;
+import java.awt.datatransfer.Transferable;
+import java.awt.datatransfer.UnsupportedFlavorException;
+import java.awt.dnd.DnDConstants;
+import java.awt.dnd.DropTarget;
+import java.awt.dnd.DropTargetDragEvent;
+import java.awt.dnd.DropTargetDropEvent;
+import java.awt.dnd.DropTargetEvent;
+import java.awt.dnd.DropTargetListener;
+import java.awt.event.ActionEvent;
+import java.awt.event.MouseEvent;
import java.awt.geom.Point2D;
import java.awt.image.BufferedImage;
import java.io.File;
@@ -19,14 +32,37 @@
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Paths;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
import java.util.List;
+import java.util.Observable;
+import java.util.Observer;
import java.util.concurrent.Executors;
import java.util.prefs.Preferences;
import javax.imageio.ImageIO;
import javax.media.opengl.GLAutoDrawable;
-import javax.swing.*;
+import javax.swing.AbstractAction;
+import javax.swing.Action;
+import javax.swing.ActionMap;
+import javax.swing.InputMap;
+import javax.swing.JCheckBoxMenuItem;
+import javax.swing.JComponent;
+import javax.swing.JMenu;
+import javax.swing.JMenuItem;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JPopupMenu;
+import javax.swing.JRadioButtonMenuItem;
+import javax.swing.JSlider;
+import javax.swing.JTextField;
+import javax.swing.KeyStroke;
+import javax.swing.SwingUtilities;
import javax.swing.event.ChangeListener;
import javax.swing.event.MouseInputAdapter;
import javax.swing.event.MouseInputListener;
@@ -36,38 +72,30 @@
import com.google.common.eventbus.Subscribe;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import com.jogamp.opengl.util.awt.AWTGLReadBufferUtil;
-
+import org.apache.commons.lang.StringUtils;
+import org.janelia.geometry3d.Matrix4;
+import org.janelia.geometry3d.MeshGeometry;
import org.janelia.geometry3d.ObservableInterface;
-import org.janelia.horta.actors.OmeZarrVolumeActor;
-import org.janelia.horta.blocks.OmeZarrBlockTileSource;
-import org.janelia.horta.omezarr.OmeZarrReaderProgressObserver;
-import org.janelia.horta.loader.*;
-import org.janelia.workstation.common.actions.CopyToClipboardAction;
-import org.janelia.workstation.controller.dialog.NeuronColorDialog;
-import org.janelia.workstation.controller.dialog.SaveOrOpenDeepLinkDialog;
-import org.janelia.workstation.controller.listener.ColorModelListener;
-import org.janelia.workstation.controller.listener.UnmixingListener;
-import org.janelia.workstation.controller.listener.NeuronVertexCreationListener;
-import org.janelia.workstation.controller.listener.NeuronVertexDeletionListener;
-import org.janelia.workstation.controller.listener.NeuronVertexUpdateListener;
-import org.janelia.workstation.controller.listener.TolerantMouseClickListener;
-import org.janelia.workstation.controller.model.color.ChannelColorModel;
-import org.janelia.workstation.controller.model.color.ColorSwatch;
-import org.janelia.workstation.controller.model.color.ImageColorModel;
-import org.janelia.workstation.controller.model.annotations.neuron.VertexCollectionWithNeuron;
-import org.janelia.workstation.controller.model.annotations.neuron.VertexWithNeuron;
-import org.janelia.geometry3d.*;
+import org.janelia.geometry3d.PerspectiveCamera;
+import org.janelia.geometry3d.Quaternion;
+import org.janelia.geometry3d.Rotation;
+import org.janelia.geometry3d.Vantage;
+import org.janelia.geometry3d.Vector3;
+import org.janelia.geometry3d.Vector4;
+import org.janelia.geometry3d.Viewport;
+import org.janelia.geometry3d.WavefrontObjLoader;
import org.janelia.gltools.GL3Actor;
import org.janelia.gltools.MeshActor;
import org.janelia.gltools.MultipassRenderer;
import org.janelia.gltools.material.TransparentEnvelope;
-import org.janelia.horta.volume.VolumeMipMaterial;
import org.janelia.horta.actions.ResetHortaRotationAction;
import org.janelia.horta.activity_logging.ActivityLogHelper;
import org.janelia.horta.actors.CenterCrossHairActor;
+import org.janelia.horta.actors.OmeZarrVolumeActor;
import org.janelia.horta.actors.ScaleBar;
import org.janelia.horta.actors.TetVolumeActor;
import org.janelia.horta.blocks.KtxOctreeBlockTileSource;
+import org.janelia.horta.blocks.OmeZarrBlockTileSource;
import org.janelia.horta.controller.HortaManager;
import org.janelia.horta.loader.DroppedFileHandler;
import org.janelia.horta.loader.GZIPFileLoader;
@@ -75,6 +103,7 @@
import org.janelia.horta.loader.HortaVolumeCache;
import org.janelia.horta.loader.LZ4FileLoader;
import org.janelia.horta.loader.ObjMeshLoader;
+import org.janelia.horta.loader.OmeZarrLoader;
import org.janelia.horta.loader.TarFileLoader;
import org.janelia.horta.loader.TgzFileLoader;
import org.janelia.horta.loader.TilebaseYamlLoader;
@@ -83,24 +112,64 @@
import org.janelia.horta.volume.BrickInfo;
import org.janelia.horta.volume.LocalVolumeBrickSource;
import org.janelia.horta.volume.StaticVolumeBrickSource;
+import org.janelia.horta.volume.VolumeMipMaterial;
+import org.janelia.jacsstorage.clients.api.JadeStorageAttributes;
+import org.janelia.jacsstorage.clients.api.http.ClientProxy;
import org.janelia.model.domain.DomainConstants;
-import org.janelia.model.domain.tiledMicroscope.*;
+import org.janelia.model.domain.enums.FileType;
+import org.janelia.model.domain.tiledMicroscope.TmColorModel;
+import org.janelia.model.domain.tiledMicroscope.TmGeoAnnotation;
+import org.janelia.model.domain.tiledMicroscope.TmNeuronMetadata;
+import org.janelia.model.domain.tiledMicroscope.TmObjectMesh;
+import org.janelia.model.domain.tiledMicroscope.TmSample;
+import org.janelia.model.domain.tiledMicroscope.TmWorkspace;
import org.janelia.rendering.RenderedVolumeLoader;
import org.janelia.rendering.RenderedVolumeLoaderImpl;
-import org.janelia.rendering.utils.ClientProxy;
import org.janelia.scenewindow.OrbitPanZoomInteractor;
import org.janelia.scenewindow.SceneRenderer;
import org.janelia.scenewindow.SceneRenderer.CameraType;
import org.janelia.scenewindow.SceneWindow;
import org.janelia.scenewindow.fps.FrameTracker;
+import org.janelia.workstation.common.actions.CopyToClipboardAction;
import org.janelia.workstation.controller.NeuronManager;
import org.janelia.workstation.controller.ViewerEventBus;
import org.janelia.workstation.controller.access.ModelTranslation;
-import org.janelia.workstation.controller.action.*;
+import org.janelia.workstation.controller.action.AddEditNoteAction;
+import org.janelia.workstation.controller.action.DeleteNeuronSubtreeAction;
+import org.janelia.workstation.controller.action.DeleteVertexLinkAction;
+import org.janelia.workstation.controller.action.NeuronDeleteAction;
+import org.janelia.workstation.controller.action.NeuronRenameAction;
+import org.janelia.workstation.controller.action.NeuronSetRadiusAction;
+import org.janelia.workstation.controller.action.RerootNeuronAction;
+import org.janelia.workstation.controller.action.SplitNeuronAtVertexAction;
+import org.janelia.workstation.controller.action.SplitNeuronBetweenVerticesAction;
+import org.janelia.workstation.controller.action.TransferNeuriteAction;
+import org.janelia.workstation.controller.dialog.NeuronColorDialog;
import org.janelia.workstation.controller.dialog.NeuronGroupsDialog;
-import org.janelia.workstation.controller.eventbus.*;
+import org.janelia.workstation.controller.dialog.SaveOrOpenDeepLinkDialog;
+import org.janelia.workstation.controller.eventbus.AnimationEvent;
+import org.janelia.workstation.controller.eventbus.ColorModelUpdateEvent;
+import org.janelia.workstation.controller.eventbus.MeshDeleteEvent;
+import org.janelia.workstation.controller.eventbus.MeshUpdateEvent;
+import org.janelia.workstation.controller.eventbus.MeshVisibilityEvent;
+import org.janelia.workstation.controller.eventbus.MovieEvent;
+import org.janelia.workstation.controller.eventbus.NeuronUpdateEvent;
+import org.janelia.workstation.controller.eventbus.ViewEvent;
+import org.janelia.workstation.controller.eventbus.ViewerCloseEvent;
+import org.janelia.workstation.controller.eventbus.ViewerOpenEvent;
+import org.janelia.workstation.controller.listener.ColorModelListener;
+import org.janelia.workstation.controller.listener.NeuronVertexCreationListener;
+import org.janelia.workstation.controller.listener.NeuronVertexDeletionListener;
+import org.janelia.workstation.controller.listener.NeuronVertexUpdateListener;
+import org.janelia.workstation.controller.listener.TolerantMouseClickListener;
+import org.janelia.workstation.controller.listener.UnmixingListener;
import org.janelia.workstation.controller.model.TmModelManager;
import org.janelia.workstation.controller.model.TmViewState;
+import org.janelia.workstation.controller.model.annotations.neuron.VertexCollectionWithNeuron;
+import org.janelia.workstation.controller.model.annotations.neuron.VertexWithNeuron;
+import org.janelia.workstation.controller.model.color.ChannelColorModel;
+import org.janelia.workstation.controller.model.color.ColorSwatch;
+import org.janelia.workstation.controller.model.color.ImageColorModel;
import org.janelia.workstation.controller.options.ApplicationPanel;
import org.janelia.workstation.core.api.LocalCacheMgr;
import org.janelia.workstation.core.api.http.RestJsonClientManager;
@@ -2328,7 +2397,7 @@ private KtxOctreeBlockTileSource createKtxSource() {
return null;
}
try {
- return new KtxOctreeBlockTileSource(getCurrentSourceURL(), getTileLoader()).init(tmSample);
+ return new KtxOctreeBlockTileSource(getCurrentSourceURL(), getTileLoader(tmSample)).init(tmSample);
} catch (Exception e) {
logger.warn("Error initializing KTX source for {}", TmModelManager.getInstance().getCurrentSample(), e);
JOptionPane.showMessageDialog(
@@ -2340,10 +2409,13 @@ private KtxOctreeBlockTileSource createKtxSource() {
}
}
- TileLoader getTileLoader() {
+ TileLoader getTileLoader(TmSample sample) {
if (ApplicationOptions.getInstance().isUseHTTPForTileAccess()) {
return new CachedTileLoader(
- new JadeBasedTileLoader(new JadeServiceClient(ConsoleProperties.getString("jadestorage.rest.url"), () -> new ClientProxy(RestJsonClientManager.getInstance().getHttpClient(true), false))),
+ new JadeBasedTileLoader(new JadeServiceClient(
+ ConsoleProperties.getString("jadestorage.rest.url"),
+ () -> new ClientProxy(RestJsonClientManager.getInstance().getHttpClient(true), false)),
+ new JadeStorageAttributes().setFromMap(sample.getStorageAttributes())),
LocalCacheMgr.getInstance().getLocalFileCacheStorage(),
CACHE_CONCURRENCY,
Executors.newFixedThreadPool(
diff --git a/modules/HortaTracer/src/main/java/org/janelia/horta/ViewLoader.java b/modules/HortaTracer/src/main/java/org/janelia/horta/ViewLoader.java
index 48c27779f4..d959873080 100644
--- a/modules/HortaTracer/src/main/java/org/janelia/horta/ViewLoader.java
+++ b/modules/HortaTracer/src/main/java/org/janelia/horta/ViewLoader.java
@@ -1,43 +1,20 @@
package org.janelia.horta;
import java.io.IOException;
-import java.net.URI;
import java.net.URL;
-import java.nio.file.Paths;
import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;
-import com.fasterxml.jackson.databind.DeserializationFeature;
-import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.base.Objects;
-
-import org.apache.commons.httpclient.DefaultHttpMethodRetryHandler;
-import org.apache.commons.httpclient.methods.GetMethod;
-import org.apache.commons.lang.StringUtils;
-import org.janelia.geometry3d.Viewport;
-import org.janelia.horta.actors.OmeZarrVolumeActor;
-import org.janelia.horta.blocks.OmeZarrBlockTileSource;
-import org.janelia.horta.omezarr.OmeZarrReaderCompletionObserver;
-import org.janelia.horta.omezarr.OmeZarrReaderProgressObserver;
-import org.janelia.workstation.controller.tileimagery.OsFilePathRemapper;
import org.janelia.geometry3d.PerspectiveCamera;
import org.janelia.geometry3d.Vantage;
import org.janelia.geometry3d.Vector3;
import org.janelia.horta.blocks.KtxOctreeBlockTileSource;
-import org.janelia.horta.util.HttpClientHelper;
+import org.janelia.horta.blocks.OmeZarrBlockTileSource;
import org.janelia.model.domain.tiledMicroscope.TmSample;
-import org.janelia.model.security.AppAuthorization;
-import org.janelia.rendering.FileBasedRenderedVolumeLocation;
-import org.janelia.rendering.JADEBasedRenderedVolumeLocation;
-import org.janelia.rendering.RenderedVolume;
-import org.janelia.rendering.RenderedVolumeLocation;
-import org.janelia.rendering.RenderedVolumeMetadata;
-import org.janelia.rendering.utils.ClientProxy;
import org.janelia.scenewindow.SceneWindow;
import org.janelia.workstation.controller.model.TmModelManager;
-import org.janelia.workstation.core.api.AccessManager;
-import org.janelia.workstation.core.api.http.RestJsonClientManager;
import org.janelia.workstation.geom.Vec3;
import org.netbeans.api.progress.ProgressHandle;
import org.netbeans.api.progress.ProgressHandleFactory;
@@ -47,12 +24,10 @@
public class ViewLoader {
private static final Logger LOG = LoggerFactory.getLogger(ViewLoader.class);
- private static final HttpClientHelper HTTP_HELPER = new HttpClientHelper();
private final NeuronTraceLoader loader;
private final NeuronTracerTopComponent nttc;
private final SceneWindow sceneWindow;
- private final ObjectMapper objectMapper;
ViewLoader(NeuronTraceLoader loader,
@@ -61,7 +36,6 @@ public class ViewLoader {
this.loader = loader;
this.nttc = nttc;
this.sceneWindow = sceneWindow;
- this.objectMapper = new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
}
public void loadView(Vec3 syncLocation, double syncZoom) throws Exception {
@@ -86,7 +60,9 @@ public void run() {
+ syncLocation.getZ());
}
- if (nttc.isPreferKtx()) {
+ if (nttc.isPreferKtx()
+ /** the next condition is to allow switching to a KTX sample after a ZARR sample */
+ || sample != null && sample.getLargeVolumeZarrFilepath() == null) {
// for KTX tile the camera must be set before the tiles are loaded in order for them to be displayed first time
progress.setDisplayName("Centering on location...");
setCameraLocation(syncZoom, syncLocation);
@@ -134,43 +110,6 @@ public void run() {
RequestProcessor.getDefault().post(task);
}
- private RenderedVolume getVolumeInfo(URI renderedOctreeUri) {
- RenderedVolumeLocation renderedVolumeLocation;
- RenderedVolumeMetadata renderedVolumeMetadata;
- if (StringUtils.equalsIgnoreCase(renderedOctreeUri.getScheme(), "http") || StringUtils.equalsIgnoreCase(renderedOctreeUri.getScheme(), "https")) {
- String url = renderedOctreeUri.resolve("volume_info").toString();
- LOG.trace("Getting volume metadata from: {}", url);
- GetMethod getMethod = new GetMethod(url);
- getMethod.getParams().setParameter("http.method.retry-handler", new DefaultHttpMethodRetryHandler(3, false));
- AppAuthorization appAuthorization = AccessManager.getAccessManager().getAppAuthorization();
- try {
- int statusCode = HTTP_HELPER.executeMethod(getMethod, appAuthorization);
- if (statusCode != 200) {
- throw new IllegalStateException("HTTP status " + statusCode + " (not OK) from url " + url);
- }
- renderedVolumeMetadata = objectMapper.readValue(getMethod.getResponseBodyAsStream(), RenderedVolumeMetadata.class);
- renderedVolumeLocation = new JADEBasedRenderedVolumeLocation(
- renderedVolumeMetadata.getConnectionURI(),
- renderedVolumeMetadata.getDataStorageURI(),
- renderedVolumeMetadata.getVolumeBasePath(),
- appAuthorization.getAuthenticationToken(),
- null,
- () -> new ClientProxy(RestJsonClientManager.getInstance().getHttpClient(true), false)
- );
- } catch (Exception e) {
- LOG.error("Error getting sample volume info from {} for renderedOctree at {}", url, renderedOctreeUri, e);
- throw new IllegalStateException(e);
- } finally {
- getMethod.releaseConnection();
- }
- } else {
- renderedVolumeLocation = new FileBasedRenderedVolumeLocation(Paths.get(renderedOctreeUri), p -> Paths.get(OsFilePathRemapper.remapLinuxPath(p.toString())));
- renderedVolumeMetadata = nttc.getRenderedVolumeLoader().loadVolume(renderedVolumeLocation).orElseThrow(() -> new IllegalStateException("No rendering information found for " + renderedVolumeLocation.getDataStorageURI()));
- }
-
- return new RenderedVolume(renderedVolumeLocation, renderedVolumeMetadata);
- }
-
private KtxOctreeBlockTileSource createKtxSource(URL renderedOctreeUrl, TmSample sample) {
KtxOctreeBlockTileSource previousSource = nttc.getKtxSource();
if (previousSource != null) {
@@ -179,7 +118,7 @@ private KtxOctreeBlockTileSource createKtxSource(URL renderedOctreeUrl, TmSample
return previousSource; // Source did not change
}
}
- return new KtxOctreeBlockTileSource(renderedOctreeUrl, nttc.getTileLoader()).init(sample);
+ return new KtxOctreeBlockTileSource(renderedOctreeUrl, nttc.getTileLoader(sample)).init(sample);
}
private OmeZarrBlockTileSource createOmeZarrSource(URL renderedOmeZarrUrl, TmSample sample, ProgressHandle progress) throws IOException {
diff --git a/modules/HortaTracer/src/main/java/org/janelia/horta/actors/TetVolumeActor.java b/modules/HortaTracer/src/main/java/org/janelia/horta/actors/TetVolumeActor.java
index 68cebe37e6..01fcc665a7 100644
--- a/modules/HortaTracer/src/main/java/org/janelia/horta/actors/TetVolumeActor.java
+++ b/modules/HortaTracer/src/main/java/org/janelia/horta/actors/TetVolumeActor.java
@@ -71,11 +71,10 @@ static public TetVolumeActor getInstance() {
private final UnmixingParameters unmixMinScale = new UnmixingParameters(new float[] {0.0f, 0.0f, 0.5f, 0.5f});
private VolumeState volumeState = new VolumeState();
- private KtxOctreeBlockTileSource source;
- private final BlockSorter blockSorter = new BlockSorter();
+ private final BlockSorter blockSorter = new BlockSorter();
private final KtxTileCache dynamicTiles = new KtxTileCache(null);
private BlockChooser chooser;
- private BlockDisplayUpdater blockDisplayUpdater;
+ private final BlockDisplayUpdater blockDisplayUpdater;
private final Collection obsoleteActors = new ArrayList<>();
// Singleton actor has private constructor
@@ -85,9 +84,8 @@ private TetVolumeActor() {
BufferedImage colorMapImage = null;
try {
colorMapImage = ImageIO.read(
- getClass().getResourceAsStream(
- "/org/janelia/horta/images/"
- + "HotColorMap.png"));
+ getClass().getResourceAsStream("/org/janelia/horta/images/HotColorMap.png")
+ );
} catch (IOException ex) {
Exceptions.printStackTrace(ex);
}
@@ -144,7 +142,6 @@ public void setHortaVantage(Vantage vantage) {
public void setKtxTileSource(KtxOctreeBlockTileSource source) {
dynamicTiles.setSource(source);
blockDisplayUpdater.setBlockTileSource(source);
- this.source = source;
}
public ObservableInterface getDynamicTileUpdateObservable() {
@@ -182,9 +179,7 @@ public void display(GL3 gl, AbstractCamera camera, Matrix4 parentModelViewMatrix
if (! isInitialized) init(gl);
if (! dynamicTiles.canDisplay()) {
- if (getChildren() == null)
- return;
- if (getChildren().size() < 1)
+ if (getChildren() == null || getChildren().isEmpty())
return;
}
@@ -274,18 +269,18 @@ public void display(GL3 gl, AbstractCamera camera, Matrix4 parentModelViewMatrix
c2.isVisible() ? 1.0f : 0.0f
}, 0);
// color
- float hsv0[] = new float[3];
- float hsv1[] = new float[3];
- float hsv2[] = new float[3];
+ float[] hsv0 = new float[3];
+ float[] hsv1 = new float[3];
+ float[] hsv2 = new float[3];
Color.RGBtoHSB(c0.getColor().getRed(), c0.getColor().getGreen(), c0.getColor().getBlue(), hsv0);
Color.RGBtoHSB(c1.getColor().getRed(), c1.getColor().getGreen(), c1.getColor().getBlue(), hsv1);
Color.RGBtoHSB(c2.getColor().getRed(), c2.getColor().getGreen(), c2.getColor().getBlue(), hsv2);
- float hues[] = new float[] {360.0f*hsv0[0], 360.0f*hsv1[0], 360.0f*hsv2[0]};
- float saturations[] = new float[] {hsv0[1], hsv1[1], hsv2[1]};
-
+ float[] hues = new float[] {360.0f*hsv0[0], 360.0f*hsv1[0], 360.0f*hsv2[0]};
+ float[] saturations = new float[] {hsv0[1], hsv1[1], hsv2[1]};
+
gl.glUniform3fv(11, 1, hues, 0);
gl.glUniform3fv(12, 1, saturations, 0);
-
+
// unmixing parameters
gl.glUniform4fv(7, 1, unmixMinScale.getParams(), 0);
@@ -305,18 +300,13 @@ public void display(GL3 gl, AbstractCamera camera, Matrix4 parentModelViewMatrix
// 3) Sort individual blocks by distance from camera, for
// correct transparency blending
- List blockList = new ArrayList<>();
+ List blockList = new ArrayList<>(dynamicTiles.getDisplayedActors());
List otherActorList = new ArrayList<>();
List otherList = new ArrayList<>();
- for (SortableBlockActor actor : dynamicTiles.getDisplayedActors()) {
- blockList.add(actor);
- }
for (Object3d child : getChildren()) {
if (child instanceof SortableBlockActorSource) {
SortableBlockActorSource source = (SortableBlockActorSource)child;
- for (SortableBlockActor block : source.getSortableBlockActors()) {
- blockList.add(block);
- }
+ blockList.addAll(source.getSortableBlockActors());
}
else if (child instanceof GL3Actor) {
otherActorList.add((GL3Actor)child);
@@ -331,7 +321,7 @@ else if (child instanceof GL3Actor) {
// Order does not matter in MIP mode
if (volumeState.projectionMode != VolumeState.PROJECTION_MAXIMUM) {
blockSorter.setViewMatrix(modelViewMatrix);
- Collections.sort(blockList, blockSorter);
+ blockList.sort(blockSorter);
}
// 4) Display blocks
diff --git a/modules/HortaTracer/src/main/java/org/janelia/horta/blocks/OmeZarrBlockTileSource.java b/modules/HortaTracer/src/main/java/org/janelia/horta/blocks/OmeZarrBlockTileSource.java
index 9cf297ec1a..b8b6803f1c 100644
--- a/modules/HortaTracer/src/main/java/org/janelia/horta/blocks/OmeZarrBlockTileSource.java
+++ b/modules/HortaTracer/src/main/java/org/janelia/horta/blocks/OmeZarrBlockTileSource.java
@@ -11,6 +11,7 @@
import org.janelia.horta.omezarr.OmeZarrJadeReader;
import org.janelia.horta.omezarr.OmeZarrReaderProgressObserver;
import org.janelia.horta.omezarr.OmeZarrReaderCompletionObserver;
+import org.janelia.jacsstorage.clients.api.JadeStorageAttributes;
import org.janelia.model.domain.enums.FileType;
import org.janelia.model.domain.tiledMicroscope.TmSample;
import org.janelia.workstation.controller.model.color.ImageColorModel;
@@ -80,7 +81,9 @@ public OmeZarrBlockTileSource init(TmSample sample) throws IOException {
public OmeZarrBlockTileSource init(TmSample sample, OmeZarrReaderProgressObserver progressObserver, OmeZarrReaderCompletionObserver completionObserver) throws IOException {
this.sampleOmeZarrTilesBaseDir = StringUtils.appendIfMissing(sample.getFiles().get(FileType.LargeVolumeZarr), "/");
- this.reader = new OmeZarrJadeReader(FileMgr.getFileMgr().getStorageService(), this.sampleOmeZarrTilesBaseDir);
+ JadeStorageAttributes storageAttributes = new JadeStorageAttributes()
+ .setFromMap(sample.getStorageAttributes());
+ this.reader = new OmeZarrJadeReader(FileMgr.getFileMgr().getStorageService(), this.sampleOmeZarrTilesBaseDir, storageAttributes);
omeZarrGroup = OmeZarrGroup.open(new JadeZarrStoreProvider("", reader));
diff --git a/modules/HortaTracer/src/main/java/org/janelia/horta/omezarr/OmeZarrJadeReader.java b/modules/HortaTracer/src/main/java/org/janelia/horta/omezarr/OmeZarrJadeReader.java
index 2246aeb192..7fc69f6639 100644
--- a/modules/HortaTracer/src/main/java/org/janelia/horta/omezarr/OmeZarrJadeReader.java
+++ b/modules/HortaTracer/src/main/java/org/janelia/horta/omezarr/OmeZarrJadeReader.java
@@ -1,5 +1,7 @@
package org.janelia.horta.omezarr;
+import org.apache.commons.lang.StringUtils;
+import org.janelia.jacsstorage.clients.api.JadeStorageAttributes;
import org.janelia.jacsstorage.clients.api.JadeStorageService;
import org.janelia.jacsstorage.clients.api.StorageLocation;
import org.janelia.jacsstorage.clients.api.StorageObject;
@@ -9,6 +11,7 @@
import java.io.IOException;
import java.io.InputStream;
+import java.net.URI;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.stream.Stream;
@@ -24,10 +27,10 @@ public class OmeZarrJadeReader {
protected final String basePath;
- public OmeZarrJadeReader(final JadeStorageService jadeStorage, final String basePath) throws IOException {
+ public OmeZarrJadeReader(final JadeStorageService jadeStorage, final String basePath, JadeStorageAttributes storageAttributes) throws IOException {
this.jadeStorage = jadeStorage;
this.basePath = basePath;
- this.storageLocation = jadeStorage.getStorageLocationByPath(basePath);
+ this.storageLocation = jadeStorage.getStorageLocationByPath(basePath, storageAttributes);
if (storageLocation == null) {
throw new IOException("Could not find Jade location for path: " + basePath);
@@ -39,8 +42,9 @@ public String getBasePath() {
}
public InputStream getInputStream(String location) {
- final Path path = Paths.get(basePath, location);
- String relativePath = storageLocation.getRelativePath(path.toString().replace("\\", "/"));
+ String l = StringUtils.isBlank(location) ? "" : location.replace('\\', '/');
+ final String path = URI.create(basePath).resolve(l).toString();
+ String relativePath = storageLocation.getRelativePath(path);
return jadeStorage.getContent(storageLocation, relativePath);
}
@@ -55,7 +59,7 @@ public String[] list(final String pathName) throws IOException {
final Path path = Paths.get(basePath, pathName);
String relativePath = storageLocation.getRelativePath(path.toString());
- try (Stream stream = jadeStorage.getChildren(storageLocation, relativePath).stream()) {
+ try (Stream stream = jadeStorage.getChildren(storageLocation, relativePath, true).stream()) {
return stream
.filter(a -> a.isCollection())
.map(a -> path.relativize(Paths.get(a.getAbsolutePath())).toString())
diff --git a/modules/IntegrationAPIs/pom.xml b/modules/IntegrationAPIs/pom.xml
index 7e46fe5a97..c5cf232786 100644
--- a/modules/IntegrationAPIs/pom.xml
+++ b/modules/IntegrationAPIs/pom.xml
@@ -5,14 +5,14 @@
org.janelia
workstation
- 9.20.1
+ 9.21.RC4
../..
IntegrationAPIs
org.janelia.workstation
integration
- 9.20.1
+ 9.21.RC4
nbm
diff --git a/modules/Jogl213Lib/pom.xml b/modules/Jogl213Lib/pom.xml
index 7b351b1a8d..be2b9eb3f5 100644
--- a/modules/Jogl213Lib/pom.xml
+++ b/modules/Jogl213Lib/pom.xml
@@ -5,14 +5,14 @@
org.janelia
workstation
- 9.20.1
+ 9.21.RC4
../..
Jogl213Lib
org.janelia.workstation
jogl213lib
- 9.20.1
+ 9.21.RC4
nbm
diff --git a/modules/Jogl224Lib/pom.xml b/modules/Jogl224Lib/pom.xml
index 1f5335eb02..bf60f189a7 100644
--- a/modules/Jogl224Lib/pom.xml
+++ b/modules/Jogl224Lib/pom.xml
@@ -5,14 +5,14 @@
org.janelia
workstation
- 9.20.1
+ 9.21.RC4
../..
Jogl224Lib
org.janelia.workstation
jogl224lib
- 9.20.1
+ 9.21.RC4
nbm
diff --git a/modules/LMDataBrowser/pom.xml b/modules/LMDataBrowser/pom.xml
index 4b13efd2b5..160ab0f61b 100644
--- a/modules/LMDataBrowser/pom.xml
+++ b/modules/LMDataBrowser/pom.xml
@@ -5,14 +5,14 @@
org.janelia
workstation
- 9.20.1
+ 9.21.RC4
../..
LMDataBrowser
org.janelia.workstation
lmdatabrowser
- 9.20.1
+ 9.21.RC4
nbm
diff --git a/modules/LMDataBrowser/src/main/java/org/janelia/workstation/lm/gui/dialogs/ImportImageFilesDialog.java b/modules/LMDataBrowser/src/main/java/org/janelia/workstation/lm/gui/dialogs/ImportImageFilesDialog.java
index a2f20f0eb3..83e731e994 100644
--- a/modules/LMDataBrowser/src/main/java/org/janelia/workstation/lm/gui/dialogs/ImportImageFilesDialog.java
+++ b/modules/LMDataBrowser/src/main/java/org/janelia/workstation/lm/gui/dialogs/ImportImageFilesDialog.java
@@ -561,7 +561,8 @@ private Long startImportFilesTask(File selectedFile,
return asyncServiceClient.invokeService("dataTreeLoad",
serviceArgsBuilder.build(),
"LSF_JAVA",
- ImmutableMap.of()
+ ImmutableMap.of(),
+ ImmutableMap.of() // invocation headers
);
}
diff --git a/modules/LargeVolumeViewer/pom.xml b/modules/LargeVolumeViewer/pom.xml
index 779b368b40..e92a4a10d7 100644
--- a/modules/LargeVolumeViewer/pom.xml
+++ b/modules/LargeVolumeViewer/pom.xml
@@ -5,14 +5,14 @@
org.janelia
workstation
- 9.20.1
+ 9.21.RC4
../..
LargeVolumeViewer
org.janelia.workstation
large_volume_viewer
- 9.20.1
+ 9.21.RC4
nbm
diff --git a/modules/N5Viewer/pom.xml b/modules/N5Viewer/pom.xml
index 05f507a65b..c91893c4f7 100644
--- a/modules/N5Viewer/pom.xml
+++ b/modules/N5Viewer/pom.xml
@@ -5,14 +5,14 @@
workstation
org.janelia
- 9.20.1
+ 9.21.RC4
../..
N5Viewer
org.janelia.workstation
n5viewer
- 9.20.1
+ 9.21.RC4
nbm
diff --git a/modules/N5Viewer/src/main/java/org/janelia/workstation/n5viewer/BigDataViewerTopComponent.java b/modules/N5Viewer/src/main/java/org/janelia/workstation/n5viewer/BigDataViewerTopComponent.java
index 92d518879d..c4e36f6373 100644
--- a/modules/N5Viewer/src/main/java/org/janelia/workstation/n5viewer/BigDataViewerTopComponent.java
+++ b/modules/N5Viewer/src/main/java/org/janelia/workstation/n5viewer/BigDataViewerTopComponent.java
@@ -1,6 +1,7 @@
package org.janelia.workstation.n5viewer;
import com.google.common.eventbus.Subscribe;
+import org.janelia.jacsstorage.clients.api.JadeStorageAttributes;
import org.janelia.jacsstorage.clients.api.JadeStorageService;
import org.janelia.model.domain.files.N5Container;
import org.janelia.saalfeldlab.n5.N5Reader;
@@ -104,7 +105,9 @@ public void loadData(N5Container n5Container, N5TreeNode n5TreeNode) {
JadeStorageService jadeStorage = FileMgr.getFileMgr().getStorageService();
try {
- N5Reader n5Reader = new N5JadeReader(jadeStorage, n5Container.getFilepath());
+ JadeStorageAttributes storageAttributes = new JadeStorageAttributes()
+ .setFromMap(n5Container.getStorageAttributes());
+ N5Reader n5Reader = new N5JadeReader(jadeStorage, n5Container.getFilepath(), storageAttributes);
DataSelection dataSelection = new DataSelection(n5Reader,
Collections.singletonList(n5TreeNode.getMetadata()));
this.n5Viewer = new N5Viewer(null, dataSelection, false);
@@ -121,7 +124,9 @@ public void addData(N5Container n5Container, N5TreeNode n5TreeNode) {
JadeStorageService jadeStorage = FileMgr.getFileMgr().getStorageService();
try {
- N5Reader n5Reader = new N5JadeReader(jadeStorage, n5Container.getFilepath());
+ JadeStorageAttributes storageAttributes = new JadeStorageAttributes()
+ .setFromMap(n5Container.getStorageAttributes());
+ N5Reader n5Reader = new N5JadeReader(jadeStorage, n5Container.getFilepath(), storageAttributes);
DataSelection dataSelection = new DataSelection(n5Reader,
Collections.singletonList(n5TreeNode.getMetadata()));
n5Viewer.addData(dataSelection);
diff --git a/modules/N5Viewer/src/main/java/org/janelia/workstation/n5viewer/N5ContainerNode.java b/modules/N5Viewer/src/main/java/org/janelia/workstation/n5viewer/N5ContainerNode.java
index bbe9ba80d1..0b5e393750 100644
--- a/modules/N5Viewer/src/main/java/org/janelia/workstation/n5viewer/N5ContainerNode.java
+++ b/modules/N5Viewer/src/main/java/org/janelia/workstation/n5viewer/N5ContainerNode.java
@@ -1,5 +1,6 @@
package org.janelia.workstation.n5viewer;
+import org.janelia.jacsstorage.clients.api.JadeStorageAttributes;
import org.janelia.jacsstorage.clients.api.JadeStorageService;
import org.janelia.model.domain.files.N5Container;
import org.janelia.saalfeldlab.n5.N5DatasetDiscoverer;
@@ -95,7 +96,9 @@ protected boolean createKeys(List list) {
// String relativePath = storageLocation.getRelativePath(n5Container.getFilepath());
// N5TreeNode n5RootNode = jadeStorage.getN5Tree(storageLocation, relativePath);
- N5Reader n5Reader = new N5JadeReader(jadeStorage, n5Container.getFilepath());
+ JadeStorageAttributes storageAttributes = new JadeStorageAttributes()
+ .setFromMap(n5Container.getStorageAttributes());
+ N5Reader n5Reader = new N5JadeReader(jadeStorage, n5Container.getFilepath(), storageAttributes);
N5DatasetDiscoverer datasetDiscoverer = new N5DatasetDiscoverer(
n5Reader,
Executors.newCachedThreadPool(),
diff --git a/modules/N5Viewer/src/main/java/org/janelia/workstation/n5viewer/N5JadeReader.java b/modules/N5Viewer/src/main/java/org/janelia/workstation/n5viewer/N5JadeReader.java
index d5119c9471..12c76b1fa8 100644
--- a/modules/N5Viewer/src/main/java/org/janelia/workstation/n5viewer/N5JadeReader.java
+++ b/modules/N5Viewer/src/main/java/org/janelia/workstation/n5viewer/N5JadeReader.java
@@ -2,6 +2,7 @@
import com.google.gson.GsonBuilder;
import com.google.gson.JsonElement;
+import org.janelia.jacsstorage.clients.api.JadeStorageAttributes;
import org.janelia.jacsstorage.clients.api.JadeStorageService;
import org.janelia.jacsstorage.clients.api.StorageLocation;
import org.janelia.jacsstorage.clients.api.StorageObject;
@@ -48,12 +49,13 @@ public class N5JadeReader extends AbstractGsonReader {
*/
public N5JadeReader(final JadeStorageService jadeStorage,
final String basePath,
- final GsonBuilder gsonBuilder) throws IOException {
+ final GsonBuilder gsonBuilder,
+ JadeStorageAttributes storageAttributes) throws IOException {
super(gsonBuilder);
this.jadeStorage = jadeStorage;
this.basePath = basePath;
- this.storageLocation = jadeStorage.getStorageLocationByPath(basePath);
+ this.storageLocation = jadeStorage.getStorageLocationByPath(basePath, storageAttributes);
if (storageLocation == null) {
throw new IOException("Could not find Jade location for path: "+basePath);
@@ -77,8 +79,8 @@ public N5JadeReader(final JadeStorageService jadeStorage,
* if the N5 version of the container is not compatible with this
* implementation.
*/
- public N5JadeReader(final JadeStorageService jadeStorageService, final String basePath) throws IOException {
- this(jadeStorageService, basePath, new GsonBuilder());
+ public N5JadeReader(final JadeStorageService jadeStorageService, final String basePath, JadeStorageAttributes storageAttributes) throws IOException {
+ this(jadeStorageService, basePath, new GsonBuilder(), storageAttributes);
}
/**
@@ -95,7 +97,7 @@ public boolean exists(final String pathName) {
final Path path = Paths.get(basePath, pathName);
String relativePath = storageLocation.getRelativePath(path.toString());
try {
- StorageObject metadata = jadeStorage.getMetadata(storageLocation, relativePath);
+ StorageObject metadata = jadeStorage.getMetadata(storageLocation, relativePath, true);
boolean exists = metadata != null && metadata.isCollection();
log.trace("exists {} = {}", pathName, exists);
return exists;
@@ -151,7 +153,7 @@ public String[] list(final String pathName) throws IOException {
final Path path = Paths.get(basePath, pathName);
String relativePath = storageLocation.getRelativePath(path.toString());
- try (Stream stream = jadeStorage.getChildren(storageLocation, relativePath).stream()) {
+ try (Stream stream = jadeStorage.getChildren(storageLocation, relativePath, true).stream()) {
return stream
.filter(a -> a.isCollection())
.map(a -> path.relativize(Paths.get(a.getAbsolutePath())).toString())
diff --git a/modules/SceneWindow/pom.xml b/modules/SceneWindow/pom.xml
index 393e527433..800b821af0 100644
--- a/modules/SceneWindow/pom.xml
+++ b/modules/SceneWindow/pom.xml
@@ -5,14 +5,14 @@
org.janelia
workstation
- 9.20.1
+ 9.21.RC4
../..
SceneWindow
org.janelia.workstation
scenegraph
- 9.20.1
+ 9.21.RC4
nbm
diff --git a/modules/SiteHortaCloud/pom.xml b/modules/SiteHortaCloud/pom.xml
index ceffb6ddf3..34763085c6 100644
--- a/modules/SiteHortaCloud/pom.xml
+++ b/modules/SiteHortaCloud/pom.xml
@@ -5,14 +5,14 @@
org.janelia
workstation
- 9.20.1
+ 9.21.RC4
../..
SiteHortaCloud
org.janelia.workstation
sitehortacloud
- 9.20.1
+ 9.21.RC4
nbm
diff --git a/modules/SiteJRC/pom.xml b/modules/SiteJRC/pom.xml
index 24062aa369..507c1c18d6 100644
--- a/modules/SiteJRC/pom.xml
+++ b/modules/SiteJRC/pom.xml
@@ -5,14 +5,14 @@
org.janelia
workstation
- 9.20.1
+ 9.21.RC4
../..
SiteJRC
org.janelia.workstation
sitejrc
- 9.20.1
+ 9.21.RC4
nbm
diff --git a/modules/Viewer3D/pom.xml b/modules/Viewer3D/pom.xml
index 0ae70dfb6b..d57328c850 100644
--- a/modules/Viewer3D/pom.xml
+++ b/modules/Viewer3D/pom.xml
@@ -5,14 +5,14 @@
org.janelia
workstation
- 9.20.1
+ 9.21.RC4
../..
Viewer3D
org.janelia.workstation
viewer3d
- 9.20.1
+ 9.21.RC4
nbm
diff --git a/modules/ViewerController/pom.xml b/modules/ViewerController/pom.xml
index c8b5ec208c..2e2fca6079 100644
--- a/modules/ViewerController/pom.xml
+++ b/modules/ViewerController/pom.xml
@@ -5,14 +5,14 @@
org.janelia
workstation
- 9.20.1
+ 9.21.RC4
../..
ViewerController
org.janelia.workstation
viewercontroller
- 9.20.1
+ 9.21.RC4
nbm
diff --git a/modules/ViewerController/src/main/java/org/janelia/workstation/controller/access/LoadedWorkspaceCreator.java b/modules/ViewerController/src/main/java/org/janelia/workstation/controller/access/LoadedWorkspaceCreator.java
index 7772b7763d..a98ed54b56 100644
--- a/modules/ViewerController/src/main/java/org/janelia/workstation/controller/access/LoadedWorkspaceCreator.java
+++ b/modules/ViewerController/src/main/java/org/janelia/workstation/controller/access/LoadedWorkspaceCreator.java
@@ -5,6 +5,8 @@
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
+import java.util.HashMap;
+import java.util.Map;
import java.util.concurrent.CancellationException;
import javax.swing.JButton;
@@ -14,6 +16,8 @@
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
@@ -90,9 +94,12 @@ static public void loadSWCsIntoWorkspace(TmSample sample, String workspaceName,
JFrame mainFrame = FrameworkAccess.getMainFrame();
final JDialog inputDialog = new JDialog(mainFrame, true);
final JTextField pathTextField = new JTextField();
- final JCheckBox systemOwnerCheckbox = new JCheckBox();
+ final JTextField accessKeyTextField = new JTextField();
+ final JTextField secretKeyTextField = new JTextField();
pathTextField.addKeyListener(new PathCorrectionKeyListener(pathTextField));
pathTextField.setToolTipText("Backslashes will be converted to /.");
+ final JLabel accessKeyLabel = new JLabel("Storage Access Key:");
+ final JLabel secretKeyLabel = new JLabel("Storage Secret Key:");
final JLabel workspaceNameLabel = new JLabel("Workspace Name");
final JTextField workspaceNameTextField = new JTextField();
workspaceNameTextField.setText(workspaceName);
@@ -103,13 +110,46 @@ static public void loadSWCsIntoWorkspace(TmSample sample, String workspaceName,
workspaceNameTextField.setEditable(false);
workspaceNameTextField.setFocusable(false);
inputDialog.setTitle("SWC Load-to-Workspace Parameters");
- inputDialog.setLayout(new GridLayout(6, 1));
+ inputDialog.setLayout(new GridLayout(7, 2));
inputDialog.add(workspaceNameLabel);
inputDialog.add(workspaceNameTextField);
+
inputDialog.add(new JLabel("Enter full path to input folder"));
inputDialog.add(pathTextField);
+
inputDialog.add(new JLabel("Mark all neurons as fragments"));
inputDialog.add(markAsFragmentsCheckbox);
+
+ JCheckBox storageCredentialsRequiredCheckbox = new JCheckBox();
+ inputDialog.add(new JLabel("Storage requires credentials"));
+ inputDialog.add(storageCredentialsRequiredCheckbox);
+
+ accessKeyLabel.setVisible(false);
+ accessKeyTextField.setVisible(false);
+ accessKeyLabel.setLabelFor(accessKeyTextField);
+ inputDialog.add(accessKeyLabel);
+ inputDialog.add(accessKeyTextField);
+
+ secretKeyLabel.setVisible(false);
+ secretKeyTextField.setVisible(false);
+ secretKeyLabel.setLabelFor(secretKeyTextField);
+ inputDialog.add(secretKeyLabel);
+ inputDialog.add(secretKeyTextField);
+
+ storageCredentialsRequiredCheckbox.addActionListener(e -> {
+ if (storageCredentialsRequiredCheckbox.isSelected()) {
+ accessKeyLabel.setVisible(true);
+ accessKeyTextField.setVisible(true);
+ secretKeyLabel.setVisible(true);
+ secretKeyTextField.setVisible(true);
+ } else {
+ accessKeyLabel.setVisible(false);
+ accessKeyTextField.setVisible(false);
+ secretKeyLabel.setVisible(false);
+ secretKeyTextField.setVisible(false);
+ }
+ });
+
JPanel buttonPanel = new JPanel();
buttonPanel.setLayout(new BorderLayout());
JButton cancelButton = new JButton("Cancel");
@@ -148,7 +188,8 @@ public void actionPerformed(ActionEvent ae) {
TiledMicroscopeRestClient cf = new TiledMicroscopeRestClient();
String swcFolder = bldr.toString().trim();
- if (cf.isServerPathAvailable(swcFolder, true) ) {
+ Map storageAttributes = getStorageAttributes(accessKeyTextField.getText(), secretKeyTextField.getText());
+ if (cf.isServerPathAvailable(swcFolder, true, storageAttributes) ) {
Boolean markAsFragments;
inputDialog.setVisible(false);
String neuronsOwnerKey;
@@ -164,7 +205,7 @@ public void actionPerformed(ActionEvent ae) {
}
importSWC(sample.getId(), workspaceNameTextField.getText().trim(), swcFolder, neuronsOwnerKey,
- markAsFragments, appendToExisting);
+ markAsFragments, appendToExisting, storageAttributes);
}
}
});
@@ -176,8 +217,19 @@ public void actionPerformed(ActionEvent ae) {
inputDialog.setVisible(true);
}
+ static private Map getStorageAttributes(String accessKeyField,String secretKeyField ) {
+ Map storageAttributes = new HashMap<>();
+ if (StringUtils.isNotBlank(accessKeyField)) {
+ storageAttributes.put("AccessKey", accessKeyField.trim());
+ }
+ if (StringUtils.isNotBlank(secretKeyField)) {
+ storageAttributes.put("SecretKey", secretKeyField.trim());
+ }
+ return storageAttributes;
+ }
+
static private void importSWC(Long sampleId, String workspace, String swcFolder, String neuronsOwner,
- Boolean markAsFragments, Boolean appendToExisting) {
+ Boolean markAsFragments, Boolean appendToExisting, Map storageAttributes) {
BackgroundWorker worker = new AsyncServiceMonitoringWorker() {
private String taskDisplayName;
@@ -194,7 +246,7 @@ protected void doStuff() throws Exception {
setStatus("Submitting task " + taskDisplayName);
- Long taskId = startImportSWC(sampleId, workspace, swcFolder, neuronsOwner, markAsFragments, appendToExisting);
+ Long taskId = startImportSWC(sampleId, workspace, swcFolder, neuronsOwner, markAsFragments, appendToExisting, storageAttributes);
setServiceId(taskId);
@@ -210,7 +262,8 @@ protected void doStuff() throws Exception {
}
static private Long startImportSWC(Long sampleId, String workspace, String swcFolder, String neuronsOwner,
- Boolean markAsFragments, Boolean appendToExisting) {
+ Boolean markAsFragments, Boolean appendToExisting,
+ Map storageAttributes) {
AsyncServiceClient asyncServiceClient = new AsyncServiceClient();
ImmutableList.Builder serviceArgsBuilder = ImmutableList.builder()
.add("-sampleId", sampleId.toString());
@@ -224,7 +277,8 @@ static private Long startImportSWC(Long sampleId, String workspace, String swcFo
return asyncServiceClient.invokeService("swcImport",
serviceArgsBuilder.build(),
null,
- ImmutableMap.of()
+ ImmutableMap.of(),
+ storageAttributes
);
}
diff --git a/modules/ViewerController/src/main/java/org/janelia/workstation/controller/access/ProjectInitFacadeImpl.java b/modules/ViewerController/src/main/java/org/janelia/workstation/controller/access/ProjectInitFacadeImpl.java
index dbded250b1..520fdebfba 100644
--- a/modules/ViewerController/src/main/java/org/janelia/workstation/controller/access/ProjectInitFacadeImpl.java
+++ b/modules/ViewerController/src/main/java/org/janelia/workstation/controller/access/ProjectInitFacadeImpl.java
@@ -1,25 +1,34 @@
package org.janelia.workstation.controller.access;
+import java.net.URI;
+import java.net.URL;
+
+import org.janelia.jacsstorage.clients.api.JadeStorageAttributes;
+import org.janelia.jacsstorage.clients.api.http.ClientProxy;
import org.janelia.model.domain.DomainObject;
import org.janelia.model.domain.DomainUtils;
-import org.janelia.model.domain.tiledMicroscope.TmNeuronMetadata;
import org.janelia.model.domain.tiledMicroscope.TmSample;
import org.janelia.model.domain.tiledMicroscope.TmWorkspace;
import org.janelia.model.util.MatrixUtilities;
-import org.janelia.rendering.utils.ClientProxy;
import org.janelia.workstation.controller.NeuronManager;
import org.janelia.workstation.controller.TmViewerManager;
import org.janelia.workstation.controller.ViewerEventBus;
import org.janelia.workstation.controller.eventbus.LoadMetadataEvent;
import org.janelia.workstation.controller.eventbus.LoadProjectEvent;
-import org.janelia.workstation.controller.eventbus.NeuronSpatialFilterUpdateEvent;
import org.janelia.workstation.controller.eventbus.UnloadProjectEvent;
import org.janelia.workstation.controller.model.TmModelManager;
import org.janelia.workstation.controller.model.annotations.neuron.NeuronModel;
import org.janelia.workstation.controller.scripts.spatialfilter.BoundingBoxSpatialFilter;
-import org.janelia.workstation.controller.scripts.spatialfilter.NeuronSelectionSpatialFilter;
-import org.janelia.workstation.controller.scripts.spatialfilter.NeuronSpatialFilter;
-import org.janelia.workstation.controller.tileimagery.*;
+import org.janelia.workstation.controller.tileimagery.BlockTiffOctreeLoadAdapter;
+import org.janelia.workstation.controller.tileimagery.BlockTiffOctreeTileLoaderProvider;
+import org.janelia.workstation.controller.tileimagery.FileBasedTileLoader;
+import org.janelia.workstation.controller.tileimagery.SharedVolumeImage;
+import org.janelia.workstation.controller.tileimagery.TileFormat;
+import org.janelia.workstation.controller.tileimagery.TileLoader;
+import org.janelia.workstation.controller.tileimagery.TileServer;
+import org.janelia.workstation.controller.tileimagery.TileStackCacheController;
+import org.janelia.workstation.controller.tileimagery.TileStackOctreeLoadAdapter;
+import org.janelia.workstation.controller.tileimagery.URLBasedTileLoader;
import org.janelia.workstation.core.api.AccessManager;
import org.janelia.workstation.core.api.http.RestJsonClientManager;
import org.janelia.workstation.core.api.web.JadeServiceClient;
@@ -35,11 +44,6 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import java.net.URI;
-import java.net.URL;
-import java.util.ArrayList;
-import java.util.Collection;
-
public class ProjectInitFacadeImpl implements ProjectInitFacade {
private final Logger log = LoggerFactory.getLogger(TmViewerManager.class);
DomainObject project;
@@ -47,8 +51,6 @@ public class ProjectInitFacadeImpl implements ProjectInitFacade {
TmViewerManager viewerManager;
TmModelManager modelManager;
- private static final int NUMBER_FRAGMENTS_THRESHOLD = 1000;
-
public ProjectInitFacadeImpl(DomainObject project) {
this.project = project;
viewerManager = TmViewerManager.getInstance();
@@ -86,7 +88,8 @@ protected void doStuff() throws Exception {
loader.loadData(sample);
SharedVolumeImage sharedVolumeImage = new SharedVolumeImage();
- TileServer tileServer = new TileServer(sharedVolumeImage);
+ JadeStorageAttributes storageAttributes = new JadeStorageAttributes().setFromMap(sample.getStorageAttributes());
+ TileServer tileServer = new TileServer(sharedVolumeImage, storageAttributes);
TmModelManager.getInstance().setTileServer(tileServer);
URL url = TmModelManager.getInstance().getTileLoader().getUrl();
@@ -97,8 +100,9 @@ protected void doStuff() throws Exception {
@Override
public BlockTiffOctreeLoadAdapter createLoadAdapter(String baseURI) {
+ JadeStorageAttributes storageAttributes = new JadeStorageAttributes().setFromMap(sample.getStorageAttributes());
return TileStackCacheController.createInstance(
- new TileStackOctreeLoadAdapter(tileFormat, URI.create(baseURI), concurrency));
+ new TileStackOctreeLoadAdapter(tileFormat, URI.create(baseURI), concurrency, storageAttributes));
}
});
sharedVolumeImage.loadURL(url);
@@ -115,7 +119,7 @@ public BlockTiffOctreeLoadAdapter createLoadAdapter(String baseURI) {
tileFormat.getMicronToVoxMatrix(),
"micronToVoxMatrix"));
if (DomainUtils.hasWriteAccess(sample, AccessManager.getWriterSet())) {
- TiledMicroscopeDomainMgr.getDomainMgr().save(sample);
+ TiledMicroscopeDomainMgr.getDomainMgr().save(sample, sample.getStorageAttributes());
}
}
modelManager.updateVoxToMicronMatrices();
diff --git a/modules/ViewerController/src/main/java/org/janelia/workstation/controller/access/TiledMicroscopeDomainMgr.java b/modules/ViewerController/src/main/java/org/janelia/workstation/controller/access/TiledMicroscopeDomainMgr.java
index 08ad29ac3a..2e037dabb3 100644
--- a/modules/ViewerController/src/main/java/org/janelia/workstation/controller/access/TiledMicroscopeDomainMgr.java
+++ b/modules/ViewerController/src/main/java/org/janelia/workstation/controller/access/TiledMicroscopeDomainMgr.java
@@ -74,7 +74,7 @@ public TmSample getSample(TmWorkspace workspace) throws Exception {
return getSample(workspace.getSampleRef().getTargetId());
}
- public TmSample createSample(String name, String filepath, String ktxPath, String zarrPath) throws Exception {
+ public TmSample createSample(String name, String filepath, String ktxPath, String zarrPath, Map storageAttributes) throws Exception {
LOG.debug("createTiledMicroscopeSample(name={}, filepath={})", name, filepath);
Map constants = client.getTmSampleConstants(filepath);
if (constants != null) {
@@ -91,7 +91,7 @@ public TmSample createSample(String name, String filepath, String ktxPath, Strin
DomainUtils.setFilepath(sample, FileType.LargeVolumeZarr, zarrPath);
}
// call out to server to get origin/scaling information
- TmSample persistedSample = save(sample);
+ TmSample persistedSample = save(sample, storageAttributes);
// Server should have put the sample in the Samples root folder. Refresh the Samples folder to show it in the explorer.
getModel().invalidate(tmSampleFolder);
@@ -103,11 +103,11 @@ public TmSample createSample(String name, String filepath, String ktxPath, Strin
}
}
- public TmSample save(TmSample sample) throws Exception {
+ public TmSample save(TmSample sample, Map storageAttributes) throws Exception {
LOG.debug("save({})",sample);
TmSample canonicalObject;
synchronized (this) {
- canonicalObject = getModel().putOrUpdate(sample.getId()==null ? client.create(sample) : client.update(sample));
+ canonicalObject = getModel().putOrUpdate(sample.getId()==null ? client.create(sample, storageAttributes) : client.update(sample, storageAttributes));
}
if (sample.getId()==null) {
getModel().notifyDomainObjectCreated(canonicalObject);
diff --git a/modules/ViewerController/src/main/java/org/janelia/workstation/controller/access/TiledMicroscopeRestClient.java b/modules/ViewerController/src/main/java/org/janelia/workstation/controller/access/TiledMicroscopeRestClient.java
index 43fce2b6de..f48cd34e9d 100644
--- a/modules/ViewerController/src/main/java/org/janelia/workstation/controller/access/TiledMicroscopeRestClient.java
+++ b/modules/ViewerController/src/main/java/org/janelia/workstation/controller/access/TiledMicroscopeRestClient.java
@@ -7,6 +7,7 @@
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.Entity;
+import javax.ws.rs.client.Invocation;
import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.GenericType;
import javax.ws.rs.core.MediaType;
@@ -96,14 +97,20 @@ Map getTmSampleConstants(String samplePath) {
return response.readEntity(new GenericType
-
- org.janelia.jacs-storage
- jacsstorage-api
- ${janeliaws.jacs-storage.version}
-
-
- org.janelia.jacs-storage
- jacsstorage-core
- ${janeliaws.jacs-storage.version}
-
org.janelia.jacs-storage
jacsstorage-clients