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>() {}); } - public TmSample create(TmSample tmSample) { + public TmSample create(TmSample tmSample, Map storageAttributes) { DomainQuery query = new DomainQuery(); query.setSubjectKey(AccessManager.getSubjectKey()); query.setDomainObject(tmSample); WebTarget target = getMouselightDataEndpoint("/sample"); - Response response = target - .request("application/json") - .put(Entity.json(query)); + Invocation.Builder requestInvocation = target + .request("application/json"); + if (storageAttributes.get("AccessKey") != null) { + requestInvocation.header("AccessKey", storageAttributes.get("AccessKey")); + } + if (storageAttributes.get("SecretKey") != null) { + requestInvocation.header("SecretKey", storageAttributes.get("SecretKey")); + } + Response response = requestInvocation.put(Entity.json(query)); checkBadResponse(target, response); return response.readEntity(TmSample.class); } @@ -141,14 +148,20 @@ public void createOperationLog(Long sampleId, Long workspaceId, Long neuronId, checkBadResponse(target, response); } - public TmSample update(TmSample tmSample) { + public TmSample update(TmSample tmSample, Map storageAttributes) { DomainQuery query = new DomainQuery(); query.setDomainObject(tmSample); query.setSubjectKey(AccessManager.getSubjectKey()); WebTarget target = getMouselightDataEndpoint("/sample"); - Response response = target - .request("application/json") - .post(Entity.json(query)); + Invocation.Builder requestInvocation = target + .request("application/json"); + if (storageAttributes.get("AccessKey") != null) { + requestInvocation.header("AccessKey", storageAttributes.get("AccessKey")); + } + if (storageAttributes.get("SecretKey") != null) { + requestInvocation.header("SecretKey", storageAttributes.get("SecretKey")); + } + Response response = requestInvocation.post(Entity.json(query)); checkBadResponse(target, response); return response.readEntity(TmSample.class); } @@ -462,14 +475,20 @@ String getNearestChannelFilesURL(String basePath, int[] viewerCoord) { .toString(); } - public boolean isServerPathAvailable(String serverPath, boolean directoryOnly) { + public boolean isServerPathAvailable(String serverPath, boolean directoryOnly, Map storageAttributes) { Client client = RestJsonClientManager.getInstance().getHttpClient(true); - Response response = client.target(remoteStorageUrl) + Invocation.Builder requestInvocation = client.target(remoteStorageUrl) .path("storage_content/storage_path_redirect") - .path(serverPath) .queryParam("directoryOnly", directoryOnly) - .request() - .head(); + .queryParam("contentPath", serverPath) + .request(); + if (storageAttributes.get("AccessKey") != null) { + requestInvocation.header("AccessKey", storageAttributes.get("AccessKey")); + } + if (storageAttributes.get("SecretKey") != null) { + requestInvocation.header("SecretKey", storageAttributes.get("SecretKey")); + } + Response response = requestInvocation.head(); int responseStatus = response.getStatus(); return responseStatus == 200; } diff --git a/modules/ViewerController/src/main/java/org/janelia/workstation/controller/action/SaveTiledMicroscopeSampleAction.java b/modules/ViewerController/src/main/java/org/janelia/workstation/controller/action/SaveTiledMicroscopeSampleAction.java index e24e7fe3dc..fc0fc6b5cb 100644 --- a/modules/ViewerController/src/main/java/org/janelia/workstation/controller/action/SaveTiledMicroscopeSampleAction.java +++ b/modules/ViewerController/src/main/java/org/janelia/workstation/controller/action/SaveTiledMicroscopeSampleAction.java @@ -2,6 +2,8 @@ import java.awt.Component; import java.awt.event.ActionEvent; +import java.util.HashMap; +import java.util.Map; import javax.swing.AbstractAction; import javax.swing.JOptionPane; @@ -21,7 +23,7 @@ public class SaveTiledMicroscopeSampleAction extends AbstractAction { private TmSample sample; - private String name, octreePath, ktxPath, altPath; + private String name, octreePath, ktxPath, altPath, accessKey, secretKey; private boolean rawCompressed; public SaveTiledMicroscopeSampleAction(TmSample sample) { @@ -29,7 +31,8 @@ public SaveTiledMicroscopeSampleAction(TmSample sample) { } public SaveTiledMicroscopeSampleAction(TmSample sample, String name, String octreePath, String ktxPath, String altPath, - boolean rawCompressed) { + boolean rawCompressed, + String accessKey, String secretKey) { super("Create Horta Sample"); this.sample = sample; this.name = name; @@ -37,6 +40,19 @@ public SaveTiledMicroscopeSampleAction(TmSample sample, String name, String octr this.ktxPath = ktxPath; this.altPath = altPath; this.rawCompressed = rawCompressed; + this.accessKey = accessKey; + this.secretKey = secretKey; + } + + private Map getStorageAttributes() { + Map storageAttributes = new HashMap<>(); + if (accessKey != null) { + storageAttributes.put("AccessKey", accessKey); + } + if (secretKey != null) { + storageAttributes.put("SecretKey", secretKey); + } + return storageAttributes; } @Override @@ -63,10 +79,10 @@ protected void doStuff() throws Exception { if (altPath != null) { DomainUtils.setFilepath(sample, FileType.LargeVolumeZarr, altPath); } - newSample = TiledMicroscopeDomainMgr.getDomainMgr().save(sample); - } - else { - newSample = TiledMicroscopeDomainMgr.getDomainMgr().createSample(name, octreePath, ktxPath, altPath); + + newSample = TiledMicroscopeDomainMgr.getDomainMgr().save(sample, getStorageAttributes()); + } else { + newSample = TiledMicroscopeDomainMgr.getDomainMgr().createSample(name, octreePath, ktxPath, altPath, getStorageAttributes()); } } diff --git a/modules/ViewerController/src/main/java/org/janelia/workstation/controller/dialog/NewTiledMicroscopeSampleDialog.java b/modules/ViewerController/src/main/java/org/janelia/workstation/controller/dialog/NewTiledMicroscopeSampleDialog.java index cb9b606e12..22c4b79a6c 100644 --- a/modules/ViewerController/src/main/java/org/janelia/workstation/controller/dialog/NewTiledMicroscopeSampleDialog.java +++ b/modules/ViewerController/src/main/java/org/janelia/workstation/controller/dialog/NewTiledMicroscopeSampleDialog.java @@ -3,6 +3,8 @@ import java.awt.BorderLayout; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; import java.io.File; @@ -24,6 +26,9 @@ public class NewTiledMicroscopeSampleDialog extends ModalDialog { private final JTextField pathToOctreeTextField = new JTextField(40); private final JTextField pathToKTXTextField = new JTextField(40); private final JTextField pathToOmeZarrFormatTextField = new JTextField(40); + private final JCheckBox storageCredentialsRequiredCheckbox = new JCheckBox(); + private final JTextField storageAccessKeyTextField = new JTextField(40); + private final JTextField storageSecretKeyTextField = new JTextField(40); private final JCheckBox rawCompressedField = new JCheckBox(); private final JComboBox sampleFormat = new JComboBox<>(new String[] {ktxSample, zarrSample}); @@ -86,6 +91,47 @@ public NewTiledMicroscopeSampleDialog() { c.gridx = 1; attrPanel.add(pathToOmeZarrFormatTextField, c); + c.gridx = 0; + c.gridy = 5; + JLabel storageCredentialsRequiredLabel = new JLabel("Storage requires credentials"); + attrPanel.add(storageCredentialsRequiredLabel, c); + c.gridx = 1; + attrPanel.add(storageCredentialsRequiredCheckbox, c); + + JLabel accessKeyLabel = new JLabel("Storage Access Key:"); + accessKeyLabel.setLabelFor(storageAccessKeyTextField); + c.gridx = 0; + c.gridy = 6; + attrPanel.add(accessKeyLabel, c); + c.gridx = 1; + attrPanel.add(storageAccessKeyTextField, c); + accessKeyLabel.setVisible(false); + storageAccessKeyTextField.setVisible(false); + + JLabel secretKeyLabel = new JLabel("Storage Secret Key:"); + secretKeyLabel.setLabelFor(storageSecretKeyTextField); + c.gridx = 0; + c.gridy = 7; + attrPanel.add(secretKeyLabel, c); + c.gridx = 1; + attrPanel.add(storageSecretKeyTextField, c); + secretKeyLabel.setVisible(false); + storageSecretKeyTextField.setVisible(false); + + storageCredentialsRequiredCheckbox.addActionListener(e -> { + if (storageCredentialsRequiredCheckbox.isSelected()) { + accessKeyLabel.setVisible(true); + storageAccessKeyTextField.setVisible(true); + secretKeyLabel.setVisible(true); + storageSecretKeyTextField.setVisible(true); + } else { + accessKeyLabel.setVisible(false); + storageAccessKeyTextField.setVisible(false); + secretKeyLabel.setVisible(false); + storageSecretKeyTextField.setVisible(false); + } + }); + // Zarr selections sampleFormat.addItemListener(new ItemListener() { @Override @@ -182,6 +228,8 @@ private void save() { String octree = pathToOctreeTextField.getText(); String ktx = StringUtils.isBlank(pathToKTXTextField.getText()) ? null : pathToKTXTextField.getText(); String alt = StringUtils.isBlank(pathToOmeZarrFormatTextField.getText()) ? null : pathToOmeZarrFormatTextField.getText(); + String accessKey = StringUtils.isBlank(storageAccessKeyTextField.getText()) ? null : storageAccessKeyTextField.getText(); + String secretKey = StringUtils.isBlank(storageSecretKeyTextField.getText()) ? null : storageSecretKeyTextField.getText(); if (sampleFormat.getSelectedItem()==ktxSample && octree.isEmpty()) { JOptionPane.showMessageDialog(FrameworkAccess.getMainFrame(), "You must specify both a sample name and location!", @@ -202,7 +250,9 @@ private void save() { name = file.getName(); } - Action action = new SaveTiledMicroscopeSampleAction(sample, name, octree, ktx, alt, rawCompressedField.isSelected()); + Action action = new SaveTiledMicroscopeSampleAction( + sample, name, octree, ktx, alt, rawCompressedField.isSelected(), accessKey, secretKey + ); action.actionPerformed(null); NewTiledMicroscopeSampleDialog.this.dispose(); } diff --git a/modules/ViewerController/src/main/java/org/janelia/workstation/controller/tileimagery/CachedRenderedVolumeLocation.java b/modules/ViewerController/src/main/java/org/janelia/workstation/controller/tileimagery/CachedRenderedVolumeLocation.java index 4bed18a5c8..3f879bfcd9 100644 --- a/modules/ViewerController/src/main/java/org/janelia/workstation/controller/tileimagery/CachedRenderedVolumeLocation.java +++ b/modules/ViewerController/src/main/java/org/janelia/workstation/controller/tileimagery/CachedRenderedVolumeLocation.java @@ -147,7 +147,6 @@ public boolean exists(boolean alwaysCheck) { public boolean deleteProxy() { return false; } - } @Override diff --git a/modules/ViewerController/src/main/java/org/janelia/workstation/controller/tileimagery/JadeDataClient.java b/modules/ViewerController/src/main/java/org/janelia/workstation/controller/tileimagery/JadeDataClient.java deleted file mode 100644 index 4bfcb582c1..0000000000 --- a/modules/ViewerController/src/main/java/org/janelia/workstation/controller/tileimagery/JadeDataClient.java +++ /dev/null @@ -1,33 +0,0 @@ -package org.janelia.workstation.controller.tileimagery; - -import org.janelia.rendering.utils.ClientProxy; -import org.janelia.workstation.core.api.http.RestJsonClientManager; -import org.janelia.workstation.core.api.web.JadeServiceClient; -import org.janelia.workstation.core.util.ConsoleProperties; - -public class JadeDataClient { - static JadeDataClient instance; - JadeServiceClient client; - - public static JadeDataClient getInstance() { - if (instance==null) { - instance = new JadeDataClient(); - } - return instance; - } - - public JadeDataClient() { - client = new JadeServiceClient( - ConsoleProperties.getString("jadestorage.rest.url"), - () -> new ClientProxy(RestJsonClientManager.getInstance().getHttpClient(true), false) - ); - } - - public JadeServiceClient getClient() { - return client; - } - - public void setClient(JadeServiceClient client) { - this.client = client; - } -} diff --git a/modules/ViewerController/src/main/java/org/janelia/workstation/controller/tileimagery/RestServiceBasedBlockTiffOctreeLoadAdapter.java b/modules/ViewerController/src/main/java/org/janelia/workstation/controller/tileimagery/RestServiceBasedBlockTiffOctreeLoadAdapter.java index 175759a2ca..4904761507 100644 --- a/modules/ViewerController/src/main/java/org/janelia/workstation/controller/tileimagery/RestServiceBasedBlockTiffOctreeLoadAdapter.java +++ b/modules/ViewerController/src/main/java/org/janelia/workstation/controller/tileimagery/RestServiceBasedBlockTiffOctreeLoadAdapter.java @@ -12,15 +12,16 @@ import org.apache.commons.httpclient.methods.GetMethod; import org.apache.commons.httpclient.params.HttpMethodParams; import org.janelia.it.jacs.shared.utils.HttpClientHelper; +import org.janelia.jacsstorage.clients.api.JadeStorageAttributes; +import org.janelia.jacsstorage.clients.api.rendering.JadeBasedRenderedVolumeLocation; import org.janelia.model.security.AppAuthorization; -import org.janelia.rendering.JADEBasedRenderedVolumeLocation; import org.janelia.rendering.RenderedVolumeLoader; import org.janelia.rendering.RenderedVolumeLoaderImpl; import org.janelia.rendering.RenderedVolumeLocation; import org.janelia.rendering.RenderedVolumeMetadata; import org.janelia.rendering.TileInfo; import org.janelia.rendering.TileKey; -import org.janelia.rendering.utils.ClientProxy; +import org.janelia.jacsstorage.clients.api.http.ClientProxy; import org.janelia.workstation.core.api.LocalCacheMgr; import org.janelia.workstation.core.api.http.RestJsonClientManager; import org.slf4j.Logger; @@ -42,6 +43,7 @@ public class RestServiceBasedBlockTiffOctreeLoadAdapter extends BlockTiffOctreeL // Metadata: file location required for local system as mount point. private final ObjectMapper objectMapper; + private final JadeStorageAttributes storageAttributes; private final AppAuthorization appAuthorization; private final RenderedVolumeLoader renderedVolumeLoader; private final int concurrency; @@ -51,8 +53,10 @@ public class RestServiceBasedBlockTiffOctreeLoadAdapter extends BlockTiffOctreeL RestServiceBasedBlockTiffOctreeLoadAdapter(TileFormat tileFormat, URI volumeBaseURI, int concurrency, + JadeStorageAttributes storageAttributes, AppAuthorization appAuthorization) { super(tileFormat, volumeBaseURI); + this.storageAttributes = storageAttributes; this.appAuthorization = appAuthorization; this.renderedVolumeLoader = new RenderedVolumeLoaderImpl(); this.concurrency = concurrency; @@ -75,12 +79,13 @@ public void loadMetadata() { String strData = getMethod.getResponseBodyAsString(); renderedVolumeMetadata = objectMapper.readValue(strData, RenderedVolumeMetadata.class); renderedVolumeLocation = new CachedRenderedVolumeLocation( - new JADEBasedRenderedVolumeLocation( + new JadeBasedRenderedVolumeLocation( renderedVolumeMetadata.getConnectionURI(), renderedVolumeMetadata.getDataStorageURI(), renderedVolumeMetadata.getVolumeBasePath(), appAuthorization.getAuthenticationToken(), null, + storageAttributes, () -> new ClientProxy(RestJsonClientManager.getInstance().getHttpClient(true), false) ), LocalCacheMgr.getInstance().getLocalFileCacheStorage(), diff --git a/modules/ViewerController/src/main/java/org/janelia/workstation/controller/tileimagery/TileServer.java b/modules/ViewerController/src/main/java/org/janelia/workstation/controller/tileimagery/TileServer.java index 6346ea8a41..5a1f8b2d6c 100644 --- a/modules/ViewerController/src/main/java/org/janelia/workstation/controller/tileimagery/TileServer.java +++ b/modules/ViewerController/src/main/java/org/janelia/workstation/controller/tileimagery/TileServer.java @@ -11,6 +11,8 @@ import java.util.List; import java.util.Map; import java.util.Set; + +import org.janelia.jacsstorage.clients.api.JadeStorageAttributes; import org.janelia.workstation.geom.CoordinateAxis; import org.janelia.workstation.controller.listener.LoadStatusListener; import org.janelia.workstation.controller.listener.StatusUpdateListener; @@ -42,9 +44,9 @@ public enum LoadStatus { private LoadStatus loadStatus = LoadStatus.UNINITIALIZED; // One thread pool to load minimal representation of volume - private final TexturePreFetcher minResPreFetcher; //!!!! = new TexturePreFetcher(MIN_RES_TILE_LOADER_CONCURRENCY, MIN_RES_TILE_LOADER_CONCURRENCY); + private TexturePreFetcher minResPreFetcher; // One thread pool to load current and prefetch textures - private final TexturePreFetcher futurePreFetcher; //!!!! = new TexturePreFetcher(MIN_RES_TILE_LOADER_CONCURRENCY, HIGHER_RES_TILE_LOADER_CONCURRENCY); + private TexturePreFetcher futurePreFetcher; // Refactoring 6/12/2013 private SharedVolumeImage sharedVolumeImage; @@ -60,22 +62,17 @@ public enum LoadStatus { // New path for handling tile updates July 9, 2013 cmb private Set currentDisplayTiles = new HashSet<>(); - public TileServer(SharedVolumeImage sharedVolumeImage) { - this.minResPreFetcher = new TexturePreFetcher(MIN_RES_TILE_LOADER_CONCURRENCY, MIN_RES_TILE_LOADER_CONCURRENCY); - this.futurePreFetcher = new TexturePreFetcher(MIN_RES_TILE_LOADER_CONCURRENCY, HIGHER_RES_TILE_LOADER_CONCURRENCY); - + public TileServer(SharedVolumeImage sharedVolumeImage, JadeStorageAttributes storageAttributes) { setSharedVolumeImage(sharedVolumeImage.setTileLoaderProvider(new BlockTiffOctreeTileLoaderProvider() { int concurrency = HIGHER_RES_TILE_LOADER_CONCURRENCY; @Override public BlockTiffOctreeLoadAdapter createLoadAdapter(String baseURI) { return TileStackCacheController.createInstance( - new TileStackOctreeLoadAdapter(new TileFormat(), URI.create(baseURI), concurrency)); + new TileStackOctreeLoadAdapter(new TileFormat(), URI.create(baseURI), concurrency, storageAttributes)); } })); - minResPreFetcher.setTextureCache(getTextureCache()); - futurePreFetcher.setTextureCache(getTextureCache()); queueDrainedListener = new StatusUpdateListener() { @Override public void update() { @@ -97,8 +94,14 @@ private void startMinResPreFetch() { if (!sharedVolumeImage.isLoaded()) { return; } + if (minResPreFetcher == null) { + minResPreFetcher = new TexturePreFetcher(MIN_RES_TILE_LOADER_CONCURRENCY, MIN_RES_TILE_LOADER_CONCURRENCY); + minResPreFetcher.setTextureCache(getTextureCache()); + minResPreFetcher.setLoadAdapter(sharedVolumeImage.getLoadAdapter()); + } else { + minResPreFetcher.clear(); + } // queue load of all low resolution textures - minResPreFetcher.clear(); TileFormat format = sharedVolumeImage.getLoadAdapter().getTileFormat(); List generators = new ArrayList<>(); if (format.isHasXSlices()) { @@ -156,17 +159,18 @@ public void clearCache() { if (textureIds != null) { textureCache.getHistoryCache().storeObsoleteTextureIds(textureIds); // so old texture ids can get deleted next draw } - minResPreFetcher.setTextureCache(textureCache); - futurePreFetcher.setTextureCache(textureCache); + if (minResPreFetcher != null) { + minResPreFetcher.setTextureCache(textureCache); + } + if (futurePreFetcher != null) { + futurePreFetcher.setTextureCache(textureCache); + } for (ViewTileManager vtm : viewTileManagers) { vtm.clear(); vtm.setTextureCache(textureCache); } - if (!VolumeCache.useVolumeCache()) { - startMinResPreFetch(); - } } - + public TileSet createLatestTiles() { TileSet result = new TileSet(); for (ViewTileManager vtm : viewTileManagers) { @@ -256,7 +260,17 @@ private void rearrangeLoadQueue(TileSet currentTiles) { } updateLoadStatus(); - futurePreFetcher.clear(); + if (!VolumeCache.useVolumeCache()) { + startMinResPreFetch(); + } + + if (futurePreFetcher == null) { + futurePreFetcher = new TexturePreFetcher(MIN_RES_TILE_LOADER_CONCURRENCY, HIGHER_RES_TILE_LOADER_CONCURRENCY); + futurePreFetcher.setTextureCache(getTextureCache()); + futurePreFetcher.setLoadAdapter(sharedVolumeImage.getLoadAdapter()); + } else { + futurePreFetcher.clear(); + } Set cacheableTextures = new HashSet(); int maxCacheable = (int) (0.90 * getTextureCache().getFutureCache().getMaxSize()); @@ -413,8 +427,14 @@ public void componentHidden(ComponentEvent e) { } public void stop() { - minResPreFetcher.clear(); - futurePreFetcher.clear(); + if (minResPreFetcher != null) { + minResPreFetcher.clear(); + minResPreFetcher = null; + } + if (futurePreFetcher != null) { + futurePreFetcher.clear(); + futurePreFetcher = null; + } } //-------------------------------------------IMPLEMENTS VolumeLoadListener @@ -423,11 +443,8 @@ public void volumeLoaded(URL url) { if (sharedVolumeImage == null) { return; } - // Initialize pre-fetchers - minResPreFetcher.setLoadAdapter(sharedVolumeImage.getLoadAdapter()); - futurePreFetcher.setLoadAdapter(sharedVolumeImage.getLoadAdapter()); clearCache(); - refreshCurrentTileSet(); +// refreshCurrentTileSet(); } } diff --git a/modules/ViewerController/src/main/java/org/janelia/workstation/controller/tileimagery/TileStackOctreeLoadAdapter.java b/modules/ViewerController/src/main/java/org/janelia/workstation/controller/tileimagery/TileStackOctreeLoadAdapter.java index a48f641485..b6bd4b5347 100644 --- a/modules/ViewerController/src/main/java/org/janelia/workstation/controller/tileimagery/TileStackOctreeLoadAdapter.java +++ b/modules/ViewerController/src/main/java/org/janelia/workstation/controller/tileimagery/TileStackOctreeLoadAdapter.java @@ -2,6 +2,7 @@ import java.net.URI; +import org.janelia.jacsstorage.clients.api.JadeStorageAttributes; import org.janelia.workstation.core.api.AccessManager; /** @@ -15,12 +16,12 @@ public class TileStackOctreeLoadAdapter extends BlockTiffOctreeLoadAdapter { private final BlockTiffOctreeLoadAdapter blockTiffOctreeLoadAdapter; - public TileStackOctreeLoadAdapter(TileFormat tileFormat, URI baseURI, int concurrency) { + public TileStackOctreeLoadAdapter(TileFormat tileFormat, URI baseURI, int concurrency, JadeStorageAttributes storageAttributes) { super(tileFormat, baseURI); if (baseURI.getScheme().startsWith("file")) { blockTiffOctreeLoadAdapter = new FileBasedBlockTiffOctreeLoadAdapter(tileFormat, baseURI, concurrency); } else if (baseURI.getScheme().startsWith("http")) { - blockTiffOctreeLoadAdapter = new RestServiceBasedBlockTiffOctreeLoadAdapter(tileFormat, baseURI, concurrency, AccessManager.getAccessManager().getAppAuthorization()); + blockTiffOctreeLoadAdapter = new RestServiceBasedBlockTiffOctreeLoadAdapter(tileFormat, baseURI, concurrency, storageAttributes, AccessManager.getAccessManager().getAppAuthorization()); } else { throw new IllegalArgumentException("Don't know how to load " + baseURI); } diff --git a/modules/ViewerController/src/main/java/org/janelia/workstation/controller/tileimagery/URLBasedTileLoader.java b/modules/ViewerController/src/main/java/org/janelia/workstation/controller/tileimagery/URLBasedTileLoader.java index 41f90244c0..509487f3b3 100644 --- a/modules/ViewerController/src/main/java/org/janelia/workstation/controller/tileimagery/URLBasedTileLoader.java +++ b/modules/ViewerController/src/main/java/org/janelia/workstation/controller/tileimagery/URLBasedTileLoader.java @@ -1,21 +1,17 @@ package org.janelia.workstation.controller.tileimagery; -import org.janelia.model.domain.DomainObject; +import java.net.MalformedURLException; +import java.net.URI; + +import org.janelia.jacsstorage.clients.api.JadeStorageAttributes; +import org.janelia.jacsstorage.clients.api.rendering.JadeBasedRenderedVolumeLocation; import org.janelia.model.domain.tiledMicroscope.TmSample; -import org.janelia.rendering.JADEBasedRenderedVolumeLocation; import org.janelia.rendering.RenderedVolumeLocation; import org.janelia.workstation.core.api.web.JadeServiceClient; import org.janelia.workstation.core.util.ConsoleProperties; -import org.janelia.workstation.controller.NeuronManager; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import javax.swing.JFrame; - -import java.net.MalformedURLException; -import java.net.URI; -import java.net.URL; - public class URLBasedTileLoader extends TileLoader { private static final Logger LOG = LoggerFactory.getLogger(URLBasedTileLoader.class); @@ -52,8 +48,9 @@ public boolean loadData(TmSample sample) { @Override public RenderedVolumeLocation getRenderedVolumeLocation(TmSample tmSample) { - return jadeServiceClient.findDataLocation(tmSample.getLargeVolumeOctreeFilepath()) - .map(dataLocation -> new JADEBasedRenderedVolumeLocation(dataLocation)) + JadeStorageAttributes storageAttributes = new JadeStorageAttributes().setFromMap(tmSample.getStorageAttributes()); + return jadeServiceClient.findDataLocation(tmSample.getLargeVolumeOctreeFilepath(), storageAttributes) + .map(dataLocation -> new JadeBasedRenderedVolumeLocation(dataLocation)) .orElseThrow(() -> { LOG.warn("No jade location found for {}", tmSample); return new IllegalArgumentException("No location found for " + tmSample.getLargeVolumeOctreeFilepath()); diff --git a/modules/ViewerInfoPanel/pom.xml b/modules/ViewerInfoPanel/pom.xml index 5c52b36f26..c3fe215a89 100644 --- a/modules/ViewerInfoPanel/pom.xml +++ b/modules/ViewerInfoPanel/pom.xml @@ -5,14 +5,14 @@ org.janelia workstation - 9.20.1 + 9.21.RC4 ../.. ViewerInfoPanel org.janelia.workstation infopanel - 9.20.1 + 9.21.RC4 nbm diff --git a/modules/application/pom.xml b/modules/application/pom.xml index 74d3cf9675..29ee5fd0a3 100644 --- a/modules/application/pom.xml +++ b/modules/application/pom.xml @@ -5,14 +5,14 @@ org.janelia workstation - 9.20.1 + 9.21.RC4 ../.. Janelia Workstation org.janelia.workstation application - 9.20.1 + 9.21.RC4 nbm-application diff --git a/modules/application_horta/pom.xml b/modules/application_horta/pom.xml index 6acfaf3f2b..14cf4b0710 100644 --- a/modules/application_horta/pom.xml +++ b/modules/application_horta/pom.xml @@ -5,14 +5,14 @@ org.janelia workstation - 9.20.1 + 9.21.RC4 ../.. Horta org.janelia.workstation application_horta - 9.20.1 + 9.21.RC4 nbm-application diff --git a/modules/branding/pom.xml b/modules/branding/pom.xml index 34508512c3..45155a7a22 100644 --- a/modules/branding/pom.xml +++ b/modules/branding/pom.xml @@ -5,13 +5,13 @@ org.janelia workstation - 9.20.1 + 9.21.RC4 ../.. org.janelia.workstation branding - 9.20.1 + 9.21.RC4 nbm Branding diff --git a/pom.xml b/pom.xml index 8ddb89649d..c17be2b54a 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ Janelia Workstation org.janelia workstation - 9.20.1 + 9.21.RC4 pom @@ -75,7 +75,7 @@ RELEASE82 - 3.78 + 3.79 1.8 @@ -109,11 +109,11 @@ 9.4.46.v20220331 - 3.00 + 3.3.0 2.5.0 - 1.19.0.RELEASE + 1.22.0.RC4 @@ -380,16 +380,6 @@ jacs-messaging-core ${janeliaws.jacs-messaging.version} - - 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