diff --git a/gradle.properties b/gradle.properties
index 5413b7b20..8d928a40b 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -14,7 +14,7 @@ org.gradle.jvmargs=-Xss1M
platformVersion = 2022.1
# SemVer format -> https://semver.org
-pluginVersion = 1.2.0-221
+pluginVersion = 1.2.1-221
pluginGroup = org.zowe
pluginRepositoryUrl = https://github.com/zowe/zowe-explorer-intellij
@@ -23,4 +23,4 @@ pluginSinceBuild = 221.5080
pluginUntilBuild = 222.*
# Gradle Releases -> https://github.com/gradle/gradle/releases
-gradleVersion = 8.7.0
+gradleVersion = 8.7
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
index afba10928..e6441136f 100644
Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 20db9ad5c..b82aa23a4 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -2,5 +2,6 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
networkTimeout=10000
+validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/gradlew b/gradlew
index 65dcd68d6..1aa94a426 100755
--- a/gradlew
+++ b/gradlew
@@ -83,10 +83,8 @@ done
# This is normally unused
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
-APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
-
-# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
-DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
+# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
+APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
@@ -133,10 +131,13 @@ location of your Java installation."
fi
else
JAVACMD=java
- which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+ if ! command -v java >/dev/null 2>&1
+ then
+ die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
+ fi
fi
# Increase the maximum file descriptors if we can.
@@ -144,7 +145,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
case $MAX_FD in #(
max*)
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
- # shellcheck disable=SC3045
+ # shellcheck disable=SC2039,SC3045
MAX_FD=$( ulimit -H -n ) ||
warn "Could not query maximum file descriptor limit"
esac
@@ -152,7 +153,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
'' | soft) :;; #(
*)
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
- # shellcheck disable=SC3045
+ # shellcheck disable=SC2039,SC3045
ulimit -n "$MAX_FD" ||
warn "Could not set maximum file descriptor limit to $MAX_FD"
esac
@@ -197,11 +198,15 @@ if "$cygwin" || "$msys" ; then
done
fi
-# Collect all arguments for the java command;
-# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
-# shell script including quotes and variable substitutions, so put them in
-# double quotes to make sure that they get re-expanded; and
-# * put everything else in single quotes, so that it's not re-expanded.
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
+
+# Collect all arguments for the java command:
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
+# and any embedded shellness will be escaped.
+# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
+# treated as '${Hostname}' itself on the command line.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
diff --git a/gradlew.bat b/gradlew.bat
index 6689b85be..7101f8e46 100644
--- a/gradlew.bat
+++ b/gradlew.bat
@@ -43,11 +43,11 @@ set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if %ERRORLEVEL% equ 0 goto execute
-echo.
-echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
-echo.
-echo Please set the JAVA_HOME variable in your environment to match the
-echo location of your Java installation.
+echo. 1>&2
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
+echo. 1>&2
+echo Please set the JAVA_HOME variable in your environment to match the 1>&2
+echo location of your Java installation. 1>&2
goto fail
@@ -57,11 +57,11 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto execute
-echo.
-echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
-echo.
-echo Please set the JAVA_HOME variable in your environment to match the
-echo location of your Java installation.
+echo. 1>&2
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
+echo. 1>&2
+echo Please set the JAVA_HOME variable in your environment to match the 1>&2
+echo location of your Java installation. 1>&2
goto fail
diff --git a/src/main/kotlin/org/zowe/explorer/config/connect/connectUtils.kt b/src/main/kotlin/org/zowe/explorer/config/connect/connectUtils.kt
index d3d4edb63..e1b8cd3e4 100644
--- a/src/main/kotlin/org/zowe/explorer/config/connect/connectUtils.kt
+++ b/src/main/kotlin/org/zowe/explorer/config/connect/connectUtils.kt
@@ -19,6 +19,7 @@ import org.zowe.explorer.dataops.operations.TsoOperationMode
import org.zowe.explorer.ui.build.tso.TSOWindowFactory
import org.zowe.explorer.ui.build.tso.config.TSOConfigWrapper
import org.zowe.explorer.ui.build.tso.ui.TSOSessionParams
+import org.zowe.kotlinsdk.TsoData
/**
@@ -50,10 +51,16 @@ fun whoAmI(connectionConfig: ConnectionConfig): String? {
)
}.onSuccess {
var response = it
- response.tsoData.last().tsoMessage?.data?.let { data -> owner = data.trim() }
+ val queuedMessages: MutableList = mutableListOf()
+ queuedMessages.addAll(response.tsoData)
+
+ // consume all the TSO messages while tsoPrompt become not null
while (response.tsoData.last().tsoPrompt == null) {
response = TSOWindowFactory.getTsoMessageQueue(tsoSession)
+ queuedMessages.addAll(response.tsoData)
}
+
+ owner = tryToExtractRealOwner(queuedMessages)
}
service().performOperation(
TsoOperation(
@@ -66,6 +73,22 @@ fun whoAmI(connectionConfig: ConnectionConfig): String? {
return owner
}
+/**
+ * Utility function extracts the owner from the messages returned from the TSO request
+ * @param tsoData
+ * @return USS Owner string value if tsoData contains the userID or an empty string otherwise
+ */
+fun tryToExtractRealOwner(tsoData: List) : String {
+ val emptyOwner = ""
+ val filteredData = tsoData.filter {
+ val tsoMessage = it.tsoMessage ?: return@filter false
+ val messageData = tsoMessage.data?.trim() ?: return@filter false
+ messageData.isNotEmpty() && !messageData.contains("READY") && messageData.chars().count() < 9
+ }.mapNotNull { it.tsoMessage?.data?.trim() }
+
+ return if (filteredData.isNotEmpty()) filteredData[0] else emptyOwner
+}
+
/**
* Returns owner of particular connection config if it is not empty, or the username otherwise.
* @param connectionConfig connection config instance.
diff --git a/src/main/kotlin/org/zowe/explorer/config/connect/ui/ConnectionDialogStateBase.kt b/src/main/kotlin/org/zowe/explorer/config/connect/ui/ConnectionDialogStateBase.kt
index 4e19c0fe7..1bca0ab03 100644
--- a/src/main/kotlin/org/zowe/explorer/config/connect/ui/ConnectionDialogStateBase.kt
+++ b/src/main/kotlin/org/zowe/explorer/config/connect/ui/ConnectionDialogStateBase.kt
@@ -21,6 +21,7 @@ abstract class ConnectionDialogStateBase
abstract var connectionUuid: String
abstract var connectionName: String
abstract var username: String
+ abstract var owner: String
abstract var password: String
abstract var connectionUrl: String
abstract var credentials: Credentials
diff --git a/src/main/kotlin/org/zowe/explorer/config/connect/ui/ConnectionUssOwnerColumn.kt b/src/main/kotlin/org/zowe/explorer/config/connect/ui/ConnectionUssOwnerColumn.kt
new file mode 100644
index 000000000..b40fd4628
--- /dev/null
+++ b/src/main/kotlin/org/zowe/explorer/config/connect/ui/ConnectionUssOwnerColumn.kt
@@ -0,0 +1,48 @@
+/*
+ * This program and the accompanying materials are made available under the terms of the
+ * Eclipse Public License v2.0 which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-v20.html
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Copyright IBA Group 2020
+ */
+
+package org.zowe.explorer.config.connect.ui
+
+import com.intellij.util.ui.ColumnInfo
+import org.zowe.explorer.config.connect.ui.renderer.UssOwnerColumnRenderer
+import javax.swing.table.TableCellRenderer
+
+/**
+ * Class which represents column of USS Owner in connections GUI
+ */
+class ConnectionUssOwnerColumn>
+ : ColumnInfo("Owner") {
+
+ /**
+ * Returns name of particular owner
+ * @param item all info about particular connection to mainframe
+ * @return name of particular owner
+ */
+ override fun valueOf(item: ConnectionState): String {
+ return item.owner
+ }
+
+ /**
+ * Sets owner to particular user
+ * @param item all info about particular connection to mainframe
+ * @param value new owner of the user
+ */
+ override fun setValue(item: ConnectionState, value: String) {
+ item.owner = value
+ }
+
+ /**
+ * Specifies a renderer for this cell
+ */
+ override fun getRenderer(o: ConnectionState): TableCellRenderer {
+ return UssOwnerColumnRenderer()
+ }
+
+}
diff --git a/src/main/kotlin/org/zowe/explorer/config/connect/ui/ConnectionsTableModelBase.kt b/src/main/kotlin/org/zowe/explorer/config/connect/ui/ConnectionsTableModelBase.kt
index 050926e70..1c0d43424 100644
--- a/src/main/kotlin/org/zowe/explorer/config/connect/ui/ConnectionsTableModelBase.kt
+++ b/src/main/kotlin/org/zowe/explorer/config/connect/ui/ConnectionsTableModelBase.kt
@@ -30,7 +30,8 @@ abstract class ConnectionsTableModelBase
diff --git a/src/main/kotlin/org/zowe/explorer/config/connect/ui/renderer/UssOwnerColumnRenderer.kt b/src/main/kotlin/org/zowe/explorer/config/connect/ui/renderer/UssOwnerColumnRenderer.kt
new file mode 100644
index 000000000..ccbbb3453
--- /dev/null
+++ b/src/main/kotlin/org/zowe/explorer/config/connect/ui/renderer/UssOwnerColumnRenderer.kt
@@ -0,0 +1,52 @@
+/*
+ * This program and the accompanying materials are made available under the terms of the
+ * Eclipse Public License v2.0 which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-v20.html
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Copyright IBA Group 2020
+ */
+
+package org.zowe.explorer.config.connect.ui.renderer
+
+import com.intellij.icons.AllIcons
+import com.intellij.util.ui.table.IconTableCellRenderer
+import javax.swing.Icon
+import javax.swing.JTable
+import java.awt.Component
+
+const val WARNING_TOOLTIP_TEXT = "The last TSO request failed. Unable to get the real USS owner. The connection username will be used as USS owner"
+
+/**
+ * Renderer class for USS Owner column in the connections table view
+ */
+class UssOwnerColumnRenderer : IconTableCellRenderer() {
+
+ /**
+ * Function returns a warning icon or null if the value is not present
+ */
+ override fun getIcon(value: String, table: JTable, row: Int): Icon? {
+ return if(value.isEmpty()) AllIcons.General.Warning else null
+ }
+
+ /**
+ * Function returns a component which renders a cell
+ */
+ override fun getTableCellRendererComponent(
+ table: JTable?,
+ value: Any?,
+ selected: Boolean,
+ focus: Boolean,
+ row: Int,
+ column: Int
+ ): Component {
+ super.getTableCellRendererComponent(table, value, selected, focus, row, column)
+ if (icon != null) {
+ toolTipText = WARNING_TOOLTIP_TEXT
+ }
+ return this
+ }
+
+
+}
diff --git a/src/main/kotlin/org/zowe/explorer/config/connect/ui/zosmf/ConnectionDialog.kt b/src/main/kotlin/org/zowe/explorer/config/connect/ui/zosmf/ConnectionDialog.kt
index a3b5eb4a9..2de1f8a57 100644
--- a/src/main/kotlin/org/zowe/explorer/config/connect/ui/zosmf/ConnectionDialog.kt
+++ b/src/main/kotlin/org/zowe/explorer/config/connect/ui/zosmf/ConnectionDialog.kt
@@ -11,6 +11,9 @@
package org.zowe.explorer.config.connect.ui.zosmf
import com.intellij.icons.AllIcons
+import com.intellij.notification.Notification
+import com.intellij.notification.NotificationType
+import com.intellij.notification.Notifications
import com.intellij.openapi.components.service
import com.intellij.openapi.project.Project
import com.intellij.openapi.ui.MessageDialogBuilder
@@ -29,6 +32,7 @@ import org.zowe.explorer.config.connect.ui.ChangePasswordDialog
import org.zowe.explorer.config.connect.ui.ChangePasswordDialogState
import org.zowe.explorer.dataops.DataOpsManager
import org.zowe.explorer.dataops.operations.*
+import org.zowe.explorer.explorer.EXPLORER_NOTIFICATION_GROUP_ID
import org.zowe.explorer.utils.*
import org.zowe.explorer.utils.crudable.Crudable
import org.zowe.explorer.utils.crudable.find
@@ -147,13 +151,30 @@ class ConnectionDialog(
addAnyway
} else {
runTask(title = "Retrieving user information", project = project) {
+ // Could be empty if TSO request fails
state.owner = whoAmI(newTestedConnConfig) ?: ""
}
+ if (state.owner.isEmpty()) showWarningNotification(project)
true
}
}
)
}
+
+ /**
+ * Function shows a warning notification if USS owner cannot be retrieved
+ */
+ private fun showWarningNotification(project: Project?) {
+ Notification(
+ EXPLORER_NOTIFICATION_GROUP_ID,
+ "Unable to retrieve USS username",
+ "Cannot retrieve USS username. An error happened while executing TSO request.\n" +
+ "When working with USS files the same username will be used that was specified by the user when connecting.",
+ NotificationType.WARNING
+ ).let {
+ Notifications.Bus.notify(it, project)
+ }
+ }
}
private val initialState = state.clone()
diff --git a/src/main/kotlin/org/zowe/explorer/config/connect/ui/zosmf/ConnectionDialogState.kt b/src/main/kotlin/org/zowe/explorer/config/connect/ui/zosmf/ConnectionDialogState.kt
index 33bacef8b..2e4bfcb79 100644
--- a/src/main/kotlin/org/zowe/explorer/config/connect/ui/zosmf/ConnectionDialogState.kt
+++ b/src/main/kotlin/org/zowe/explorer/config/connect/ui/zosmf/ConnectionDialogState.kt
@@ -30,10 +30,10 @@ data class ConnectionDialogState(
/*var apiMeditationLayer: String = "",*/
override var username: String = "",
override var password: String = "",
+ override var owner: String = "",
var isAllowSsl: Boolean = false,
var zVersion: ZVersion = ZVersion.ZOS_2_1,
var zoweConfigPath: String? = null,
- var owner: String = "",
override var mode: DialogMode = DialogMode.CREATE
) : ConnectionDialogStateBase() {
diff --git a/src/main/kotlin/org/zowe/explorer/config/connect/ui/zosmf/ConnectionsTableModel.kt b/src/main/kotlin/org/zowe/explorer/config/connect/ui/zosmf/ConnectionsTableModel.kt
index ac4b2d5be..3745909bf 100644
--- a/src/main/kotlin/org/zowe/explorer/config/connect/ui/zosmf/ConnectionsTableModel.kt
+++ b/src/main/kotlin/org/zowe/explorer/config/connect/ui/zosmf/ConnectionsTableModel.kt
@@ -35,6 +35,7 @@ class ConnectionsTableModel(
get(row).isAllowSsl = item.isAllowSsl
get(row).password = item.password
get(row).zVersion = item.zVersion
+ get(row).owner = item.owner
super.set(row, item)
}
diff --git a/src/main/kotlin/org/zowe/explorer/dataops/attributes/RemoteDatasetAttributesService.kt b/src/main/kotlin/org/zowe/explorer/dataops/attributes/RemoteDatasetAttributesService.kt
index 15bfe48cc..a388626c2 100644
--- a/src/main/kotlin/org/zowe/explorer/dataops/attributes/RemoteDatasetAttributesService.kt
+++ b/src/main/kotlin/org/zowe/explorer/dataops/attributes/RemoteDatasetAttributesService.kt
@@ -100,10 +100,10 @@ class RemoteDatasetAttributesService(
val volserDir = fsModel.findOrCreate(
this, subDirectory, newAttributes.volser ?: MIGRATED, createAttributes(directory = true)
)
- fsModel.moveFile(this, file, volserDir)
+ file.move(this, volserDir)
}
if (oldAttributes.name != newAttributes.name) {
- fsModel.renameFile(this, file, newAttributes.name)
+ file.rename(this, newAttributes.name)
}
}
diff --git a/src/main/kotlin/org/zowe/explorer/dataops/attributes/RemoteJobAttributesService.kt b/src/main/kotlin/org/zowe/explorer/dataops/attributes/RemoteJobAttributesService.kt
index b98ee2a35..293e3b057 100644
--- a/src/main/kotlin/org/zowe/explorer/dataops/attributes/RemoteJobAttributesService.kt
+++ b/src/main/kotlin/org/zowe/explorer/dataops/attributes/RemoteJobAttributesService.kt
@@ -95,7 +95,7 @@ class RemoteJobAttributesService(
newAttributes: RemoteJobAttributes
) {
if (oldAttributes.name != newAttributes.name) {
- fsModel.renameFile(this, file, newAttributes.name)
+ file.rename(this, newAttributes.name)
fsModel.setWritable(file, false)
}
}
diff --git a/src/main/kotlin/org/zowe/explorer/dataops/attributes/RemoteUssAttributesService.kt b/src/main/kotlin/org/zowe/explorer/dataops/attributes/RemoteUssAttributesService.kt
index 646fdf166..f3d0852da 100644
--- a/src/main/kotlin/org/zowe/explorer/dataops/attributes/RemoteUssAttributesService.kt
+++ b/src/main/kotlin/org/zowe/explorer/dataops/attributes/RemoteUssAttributesService.kt
@@ -101,14 +101,14 @@ class RemoteUssAttributesService(
fsModel.setWritable(file, newAttributes.isWritable)
file.isReadable = newAttributes.isReadable
if (oldAttributes.name != newAttributes.name) {
- fsModel.renameFile(this, file, newAttributes.name)
+ file.rename(this, newAttributes.name)
}
if (oldAttributes.parentDirPath != newAttributes.parentDirPath) {
- var current = subDirectory
+ var current = fsRoot
createPathChain(newAttributes).dropLast(1).map { nameWithFileAttr ->
findOrCreate(current, nameWithFileAttr).also { current = it }
}
- fsModel.moveFile(this, file, current)
+ file.move(this, current)
}
}
diff --git a/src/main/kotlin/org/zowe/explorer/dataops/content/synchronizer/RemoteAttributedContentSynchronizer.kt b/src/main/kotlin/org/zowe/explorer/dataops/content/synchronizer/RemoteAttributedContentSynchronizer.kt
index 21c4d8c86..b0378ecb6 100644
--- a/src/main/kotlin/org/zowe/explorer/dataops/content/synchronizer/RemoteAttributedContentSynchronizer.kt
+++ b/src/main/kotlin/org/zowe/explorer/dataops/content/synchronizer/RemoteAttributedContentSynchronizer.kt
@@ -10,11 +10,9 @@
package org.zowe.explorer.dataops.content.synchronizer
+import com.intellij.openapi.application.runReadAction
import com.intellij.openapi.diagnostic.logger
-import com.intellij.openapi.fileEditor.FileDocumentManager
-import com.intellij.openapi.fileEditor.FileEditorManager
import com.intellij.openapi.progress.ProgressIndicator
-import com.intellij.openapi.project.ProjectManager
import com.intellij.openapi.vfs.VirtualFile
import org.zowe.explorer.dataops.DataOpsManager
import org.zowe.explorer.dataops.attributes.FileAttributes
@@ -107,29 +105,6 @@ abstract class RemoteAttributedContentSynchronizer
return fetchedAtLeastOnce.firstOrNull { syncProvider == it } != null
}
- /**
- * It is only necessary to remove old file from cache while force overwriting.
- * TODO: Not the best solution. Think on how to rework.
- * @param file - file to remove.
- */
- fun removeFromCacheAfterForceOverwriting(file: VirtualFile) {
- val syncProvider = fetchedAtLeastOnce.firstOrNull { it.file == file } ?: return
- fetchedAtLeastOnce.removeIf { it.file == file }
- // if you will not delete the file than "Local cache conflict" dialog appear.
- runWriteActionInEdtAndWait {
- // close editor if file is opened to avoid IDE crash.
- ProjectManager.getInstance().openProjects.forEach {
- syncProvider.getDocument()?.let { document ->
- val fileEditorManager = FileEditorManager.getInstance(it)
- FileDocumentManager.getInstance().getFile(document)?.let { vf ->
- fileEditorManager.closeFile(vf)
- }
- }
- }
- file.delete(this@RemoteAttributedContentSynchronizer)
- }
- }
-
/**
* Base implementation of [ContentSynchronizer.synchronizeWithRemote] method for each synchronizer.
* Doesn't need to be overridden in most cases
@@ -158,7 +133,7 @@ abstract class RemoteAttributedContentSynchronizer
fetchedAtLeastOnce.add(syncProvider)
} else {
- val fileContent = runReadActionInEdtAndWait { syncProvider.retrieveCurrentContent() }
+ val fileContent = runReadAction { syncProvider.retrieveCurrentContent() }
if (!(fileContent contentEquals adaptedFetchedBytes)) {
val oldStorageBytes = successfulStatesStorage.getBytes(recordId)
@@ -174,7 +149,7 @@ abstract class RemoteAttributedContentSynchronizer
} else {
log.info("Save strategy decided to accept remote file content.")
successfulStatesStorage.writeStream(recordId).use { it.write(adaptedFetchedBytes) }
- runWriteActionInEdt { syncProvider.loadNewContent(adaptedFetchedBytes) }
+ runWriteActionInEdtAndWait { syncProvider.loadNewContent(adaptedFetchedBytes) }
}
} else { /*do nothing*/
}
diff --git a/src/main/kotlin/org/zowe/explorer/dataops/content/synchronizer/SeqDatasetContentSynchronizer.kt b/src/main/kotlin/org/zowe/explorer/dataops/content/synchronizer/SeqDatasetContentSynchronizer.kt
index c0554ceff..590dc61c1 100644
--- a/src/main/kotlin/org/zowe/explorer/dataops/content/synchronizer/SeqDatasetContentSynchronizer.kt
+++ b/src/main/kotlin/org/zowe/explorer/dataops/content/synchronizer/SeqDatasetContentSynchronizer.kt
@@ -12,7 +12,6 @@ package org.zowe.explorer.dataops.content.synchronizer
import com.intellij.openapi.progress.ProgressIndicator
import com.intellij.openapi.vfs.VirtualFile
-import okhttp3.ResponseBody
import org.zowe.explorer.api.api
import org.zowe.explorer.api.apiWithBytesConverter
import org.zowe.explorer.config.connect.ConnectionConfig
@@ -20,8 +19,14 @@ import org.zowe.explorer.config.connect.authToken
import org.zowe.explorer.dataops.DataOpsManager
import org.zowe.explorer.dataops.attributes.RemoteDatasetAttributes
import org.zowe.explorer.dataops.exceptions.CallException
-import org.zowe.explorer.utils.*
+import org.zowe.explorer.utils.applyIfNotNull
+import org.zowe.explorer.utils.cancelByIndicator
+import org.zowe.explorer.utils.castOrNull
+import org.zowe.explorer.utils.findAnyNullable
+import org.zowe.explorer.utils.log
+import org.zowe.explorer.utils.mapNotNull
import org.zowe.explorer.vfs.MFVirtualFile
+import okhttp3.ResponseBody
import org.zowe.kotlinsdk.DataAPI
import org.zowe.kotlinsdk.DatasetOrganization
import org.zowe.kotlinsdk.XIBMDataType
@@ -186,15 +191,23 @@ class SeqDatasetContentSynchronizer(
}
/**
- * Check if the content synchronizer accepts the provided file
+ * Check if the content synchronizer accepts the provided sequential dataset virtual file
* @param file the file to check
- * @return true if the file is not migrated and the dataset organization parameter is not VS
+ * @return true if:
+ * 1. The dataset is not migrated
+ * 2. The dataset organization parameter is not VS (it is not a VSAM or VSAM-related file)
+ * 3. It is not an ALIAS
*/
override fun accepts(file: VirtualFile): Boolean {
- return super.accepts(file) &&
- dataOpsManager.tryToGetAttributes(file)?.castOrNull()?.let {
- !it.isMigrated && it.datasetInfo.datasetOrganization != DatasetOrganization.VS
- } == true
+ val isOurVFile = super.accepts(file)
+ return if (isOurVFile) {
+ val dsAttributes = attributesService.castOrNull()
+ return dsAttributes != null
+ && !dsAttributes.isMigrated
+ && dsAttributes.datasetInfo.datasetOrganization != DatasetOrganization.VS
+ && dsAttributes.datasetInfo.volumeSerial != "*ALIAS"
+ } else {
+ false
+ }
}
-
}
diff --git a/src/main/kotlin/org/zowe/explorer/dataops/content/synchronizer/SyncAction.kt b/src/main/kotlin/org/zowe/explorer/dataops/content/synchronizer/SyncAction.kt
index 3a7a66d2c..c126ffe0a 100644
--- a/src/main/kotlin/org/zowe/explorer/dataops/content/synchronizer/SyncAction.kt
+++ b/src/main/kotlin/org/zowe/explorer/dataops/content/synchronizer/SyncAction.kt
@@ -13,6 +13,7 @@ package org.zowe.explorer.dataops.content.synchronizer
import com.intellij.openapi.actionSystem.AnActionEvent
import com.intellij.openapi.actionSystem.CommonDataKeys
import com.intellij.openapi.actionSystem.ex.ActionUtil
+import com.intellij.openapi.application.runReadAction
import com.intellij.openapi.components.service
import com.intellij.openapi.editor.ex.EditorEx
import com.intellij.openapi.progress.runBackgroundableTask
@@ -69,10 +70,8 @@ class SyncAction : DumbAwareAction() {
project = e.project,
cancellable = true
) { indicator ->
- runWriteActionInEdtAndWait {
- syncProvider.saveDocument()
- service().getContentSynchronizer(vFile)?.synchronizeWithRemote(syncProvider, indicator)
- }
+ runWriteActionInEdtAndWait { syncProvider.saveDocument() }
+ service().getContentSynchronizer(vFile)?.synchronizeWithRemote(syncProvider, indicator)
}
}
@@ -108,7 +107,7 @@ class SyncAction : DumbAwareAction() {
val contentSynchronizer = service().getContentSynchronizer(file)
val syncProvider = DocumentedSyncProvider(file)
- val currentContent = runReadActionInEdtAndWait { syncProvider.retrieveCurrentContent() }
+ val currentContent = runReadAction { syncProvider.retrieveCurrentContent() }
val previousContent = contentSynchronizer?.successfulContentStorage(syncProvider)
val needToUpload = contentSynchronizer?.isFileUploadNeeded(syncProvider) == true
e.presentation.isEnabledAndVisible = file.isWritable
diff --git a/src/main/kotlin/org/zowe/explorer/dataops/operations/RenameOperationRunner.kt b/src/main/kotlin/org/zowe/explorer/dataops/operations/RenameOperationRunner.kt
index 503890b3d..dec946f2a 100644
--- a/src/main/kotlin/org/zowe/explorer/dataops/operations/RenameOperationRunner.kt
+++ b/src/main/kotlin/org/zowe/explorer/dataops/operations/RenameOperationRunner.kt
@@ -21,12 +21,8 @@ import org.zowe.explorer.dataops.exceptions.CallException
import org.zowe.explorer.explorer.actions.DuplicateMemberAction
import org.zowe.explorer.utils.cancelByIndicator
import org.zowe.explorer.utils.log
-import org.zowe.explorer.vfs.sendMFVfsChangesTopic
-import org.zowe.kotlinsdk.CopyDataZOS
-import org.zowe.kotlinsdk.DataAPI
-import org.zowe.kotlinsdk.FilePath
-import org.zowe.kotlinsdk.MoveUssFile
-import org.zowe.kotlinsdk.RenameData
+import org.zowe.explorer.utils.runWriteActionInEdtAndWait
+import org.zowe.kotlinsdk.*
/**
* Class which represents factory for rename operation runner. Defined in plugin.xml
@@ -85,7 +81,9 @@ class RenameOperationRunner(private val dataOpsManager: DataOpsManager) : Operat
toDatasetName = operation.newName
).cancelByIndicator(progressIndicator).execute()
if (response.isSuccessful) {
- sendMFVfsChangesTopic()
+ runWriteActionInEdtAndWait {
+ operation.file.rename(this, operation.newName)
+ }
} else {
throw CallException(response, "Unable to rename the selected dataset")
}
@@ -118,9 +116,7 @@ class RenameOperationRunner(private val dataOpsManager: DataOpsManager) : Operat
toDatasetName = parentAttributes.datasetInfo.name,
memberName = operation.newName
).cancelByIndicator(progressIndicator).execute()
- if (response.isSuccessful) {
- sendMFVfsChangesTopic()
- } else {
+ if (!response.isSuccessful) {
throw CallException(response, "Unable to duplicate the selected member")
}
} else {
@@ -136,7 +132,9 @@ class RenameOperationRunner(private val dataOpsManager: DataOpsManager) : Operat
memberName = operation.newName
).cancelByIndicator(progressIndicator).execute()
if (response.isSuccessful) {
- sendMFVfsChangesTopic()
+ runWriteActionInEdtAndWait {
+ operation.file.rename(this, operation.newName)
+ }
} else {
throw CallException(response, "Unable to rename the selected member")
}
@@ -164,7 +162,9 @@ class RenameOperationRunner(private val dataOpsManager: DataOpsManager) : Operat
filePath = FilePath("$parentDirPath/${operation.newName}")
).cancelByIndicator(progressIndicator).execute()
if (response.isSuccessful) {
- sendMFVfsChangesTopic()
+ runWriteActionInEdtAndWait {
+ operation.file.rename(this, operation.newName)
+ }
} else {
throw CallException(response, "Unable to rename the selected file or directory")
}
diff --git a/src/main/kotlin/org/zowe/explorer/dataops/operations/mover/RemoteToLocalFileMover.kt b/src/main/kotlin/org/zowe/explorer/dataops/operations/mover/RemoteToLocalFileMover.kt
index cca046161..f7268e35c 100644
--- a/src/main/kotlin/org/zowe/explorer/dataops/operations/mover/RemoteToLocalFileMover.kt
+++ b/src/main/kotlin/org/zowe/explorer/dataops/operations/mover/RemoteToLocalFileMover.kt
@@ -91,7 +91,7 @@ class RemoteToLocalFileMover(val dataOpsManager: DataOpsManager) : AbstractFileM
runWriteActionInEdtAndWait {
if (operation.forceOverwriting) {
- destFile.children.filter { it.name === (newFileName) && !it.isDirectory }.forEach { it.delete(this) }
+ destFile.children.filter { it.name == newFileName && !it.isDirectory }.forEach { it.delete(this) }
}
}
val createdFileJava = Paths.get(destFile.path, newFileName).toFile().apply { createNewFile() }
diff --git a/src/main/kotlin/org/zowe/explorer/editor/FileEditorEventsListener.kt b/src/main/kotlin/org/zowe/explorer/editor/FileEditorEventsListener.kt
index 3a1d6c4b5..64ad66346 100644
--- a/src/main/kotlin/org/zowe/explorer/editor/FileEditorEventsListener.kt
+++ b/src/main/kotlin/org/zowe/explorer/editor/FileEditorEventsListener.kt
@@ -11,6 +11,7 @@
package org.zowe.explorer.editor
import com.intellij.openapi.actionSystem.ex.ActionUtil
+import com.intellij.openapi.application.runReadAction
import com.intellij.openapi.components.service
import com.intellij.openapi.editor.ex.EditorEx
import com.intellij.openapi.fileEditor.FileEditorManager
@@ -77,7 +78,7 @@ class FileEditorBeforeEventsListener : FileEditorManagerListener.Before {
val attributes = dataOpsManager.tryToGetAttributes(file)
if (file is MFVirtualFile && file.isWritable && attributes != null) {
val contentSynchronizer = service().getContentSynchronizer(file)
- val currentContent = runReadActionInEdtAndWait { syncProvider.retrieveCurrentContent() }
+ val currentContent = runReadAction { syncProvider.retrieveCurrentContent() }
val previousContent = contentSynchronizer?.successfulContentStorage(syncProvider)
val needToUpload = contentSynchronizer?.isFileUploadNeeded(syncProvider) == true
if (!(currentContent contentEquals previousContent) && needToUpload) {
@@ -92,10 +93,8 @@ class FileEditorBeforeEventsListener : FileEditorManagerListener.Before {
project = project,
cancellable = true
) {
- runWriteActionInEdtAndWait {
- syncProvider.saveDocument()
- contentSynchronizer?.synchronizeWithRemote(syncProvider, it)
- }
+ runWriteActionInEdtAndWait { syncProvider.saveDocument() }
+ contentSynchronizer?.synchronizeWithRemote(syncProvider, it)
}
}
} else {
diff --git a/src/main/kotlin/org/zowe/explorer/editor/FileEditorFocusListener.kt b/src/main/kotlin/org/zowe/explorer/editor/FileEditorFocusListener.kt
index 06daf2585..40754b7b6 100644
--- a/src/main/kotlin/org/zowe/explorer/editor/FileEditorFocusListener.kt
+++ b/src/main/kotlin/org/zowe/explorer/editor/FileEditorFocusListener.kt
@@ -10,6 +10,7 @@
package org.zowe.explorer.editor
+import com.intellij.openapi.application.runReadAction
import com.intellij.openapi.components.service
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.editor.ex.EditorEx
@@ -63,7 +64,7 @@ class FileEditorFocusListener: FocusChangeListener {
if (file is MFVirtualFile && file.isWritable) {
val syncProvider = DocumentedSyncProvider(file, SaveStrategy.default(project))
val contentSynchronizer = service().getContentSynchronizer(file)
- val currentContent = runReadActionInEdtAndWait { syncProvider.retrieveCurrentContent() }
+ val currentContent = runReadAction { syncProvider.retrieveCurrentContent() }
val previousContent = contentSynchronizer?.successfulContentStorage(syncProvider)
val needToUpload = contentSynchronizer?.isFileUploadNeeded(syncProvider) == true
if (!(currentContent contentEquals previousContent) && needToUpload) {
diff --git a/src/main/kotlin/org/zowe/explorer/explorer/actions/AllocateLikeAction.kt b/src/main/kotlin/org/zowe/explorer/explorer/actions/AllocateLikeAction.kt
index 062188e36..21b0321b1 100644
--- a/src/main/kotlin/org/zowe/explorer/explorer/actions/AllocateLikeAction.kt
+++ b/src/main/kotlin/org/zowe/explorer/explorer/actions/AllocateLikeAction.kt
@@ -103,10 +103,10 @@ class AllocateLikeAction : AllocateActionBase() {
return
}
val selected = view.mySelectedNodesData
- val entityAttributes = selected[0].attributes
- e.presentation.isEnabledAndVisible = selected.size == 1
- && entityAttributes is RemoteDatasetAttributes
- && !entityAttributes.isMigrated
+ val entityAttributes = if (selected.size == 1) selected[0].attributes else null
+ e.presentation.isEnabledAndVisible = entityAttributes != null
+ && entityAttributes is RemoteDatasetAttributes
+ && !entityAttributes.isMigrated
e.presentation.icon = IconUtil.addText(AllIcons.FileTypes.Any_type, "DS")
}
diff --git a/src/main/kotlin/org/zowe/explorer/explorer/actions/EditJclAction.kt b/src/main/kotlin/org/zowe/explorer/explorer/actions/EditJclAction.kt
index 1b68231f5..89d6c1467 100644
--- a/src/main/kotlin/org/zowe/explorer/explorer/actions/EditJclAction.kt
+++ b/src/main/kotlin/org/zowe/explorer/explorer/actions/EditJclAction.kt
@@ -68,18 +68,18 @@ class EditJclAction : AnAction() {
)
val virtualFile = node.virtualFile
if (virtualFile != null) {
- runWriteActionInEdtAndWait {
- var wasCreatedBefore = true
- var cachedFile = virtualFile.findChild(attributes.name)
- if (cachedFile == null) {
- val createdFile = virtualFile.createChildData(null, attributes.name) as MFVirtualFile
- cachedFile = createdFile
- wasCreatedBefore = false
- }
- val descriptor = e.project?.let { pr -> OpenFileDescriptor(pr, cachedFile) }
- descriptor?.let {
- val syncProvider =
- DocumentedSyncProvider(file = cachedFile, saveStrategy = SaveStrategy.default(e.project))
+ var wasCreatedBefore = true
+ var cachedFile = virtualFile.findChild(attributes.name)
+ if (cachedFile == null) {
+ val createdFile = virtualFile.createChildData(null, attributes.name) as MFVirtualFile
+ cachedFile = createdFile
+ wasCreatedBefore = false
+ }
+ val descriptor = e.project?.let { pr -> OpenFileDescriptor(pr, cachedFile) }
+ descriptor?.let {
+ val syncProvider =
+ DocumentedSyncProvider(file = cachedFile, saveStrategy = SaveStrategy.default(e.project))
+ runWriteActionInEdtAndWait {
if (!wasCreatedBefore) {
syncProvider.putInitialContent(jclContentBytes)
} else {
diff --git a/src/main/kotlin/org/zowe/explorer/explorer/ui/ChangeEncodingDialog.kt b/src/main/kotlin/org/zowe/explorer/explorer/ui/ChangeEncodingDialog.kt
index 7cf1831c8..e845cbabf 100644
--- a/src/main/kotlin/org/zowe/explorer/explorer/ui/ChangeEncodingDialog.kt
+++ b/src/main/kotlin/org/zowe/explorer/explorer/ui/ChangeEncodingDialog.kt
@@ -93,10 +93,8 @@ class ChangeEncodingDialog(
val contentSynchronizer = DataOpsManager.instance.getContentSynchronizer(virtualFile)
val syncProvider = DocumentedSyncProvider(virtualFile)
if (contentSynchronizer?.isFileUploadNeeded(syncProvider) == true) {
- runWriteActionInEdtAndWait {
- syncProvider.saveDocument()
- contentSynchronizer.synchronizeWithRemote(syncProvider)
- }
+ runWriteActionInEdtAndWait { syncProvider.saveDocument() }
+ contentSynchronizer.synchronizeWithRemote(syncProvider)
}
attributes.charset = charset
updateFileTag(attributes)
diff --git a/src/main/kotlin/org/zowe/explorer/explorer/ui/ExplorerPasteProvider.kt b/src/main/kotlin/org/zowe/explorer/explorer/ui/ExplorerPasteProvider.kt
index 020992aed..a15038bac 100644
--- a/src/main/kotlin/org/zowe/explorer/explorer/ui/ExplorerPasteProvider.kt
+++ b/src/main/kotlin/org/zowe/explorer/explorer/ui/ExplorerPasteProvider.kt
@@ -21,16 +21,15 @@ import com.intellij.openapi.project.Project
import com.intellij.openapi.ui.Messages
import com.intellij.openapi.ui.showYesNoDialog
import com.intellij.openapi.vfs.VirtualFile
-import com.intellij.openapi.vfs.newvfs.impl.VirtualFileImpl
import org.zowe.explorer.common.ui.cleanInvalidateOnExpand
import org.zowe.explorer.dataops.DataOpsManager
import org.zowe.explorer.dataops.attributes.RemoteDatasetAttributes
import org.zowe.explorer.dataops.attributes.RemoteUssAttributes
-import org.zowe.explorer.dataops.content.synchronizer.RemoteAttributedContentSynchronizer
import org.zowe.explorer.dataops.operations.mover.MoveCopyOperation
import org.zowe.explorer.explorer.FileExplorerContentProvider
import org.zowe.explorer.utils.castOrNull
import org.zowe.explorer.utils.getMinimalCommonParents
+import org.zowe.explorer.utils.runWriteActionInEdt
import org.zowe.explorer.vfs.MFVirtualFile
import kotlin.concurrent.withLock
@@ -211,10 +210,7 @@ class ExplorerPasteProvider : PasteProvider {
val nameResolver = dataOpsManager.getNameResolver(op.source, op.destination)
op.destination.children
.filter { file -> file == nameResolver.getConflictingChild(op.source, op.destination) }
- .forEach { file ->
- dataOpsManager.getContentSynchronizer(file)
- .castOrNull>()?.removeFromCacheAfterForceOverwriting(file)
- }
+ .forEach { file -> runWriteActionInEdt { file.delete(this) } }
}
}
.onFailure { throwable ->
@@ -327,7 +323,7 @@ class ExplorerPasteProvider : PasteProvider {
}
.flatten()
- if (ussOrLocalFileToPdsWarnings.isNotEmpty()) {
+ if (ussOrLocalFileToPdsWarnings.isNotEmpty() && !isAllConflictsResolvedBySkip(conflictsResolutions, ussOrLocalFileToPdsWarnings.size )) {
val isLocalFilesPresent = ussOrLocalFileToPdsWarnings.find { it.second.isInLocalFileSystem } != null
val fileTypesPattern = if (isLocalFilesPresent) "Local Files" else "USS Files"
if (!showYesNoDialog(
@@ -338,9 +334,10 @@ class ExplorerPasteProvider : PasteProvider {
"Skip This Files",
AllIcons.General.WarningDialog
)) {
- conflictsResolutions.addAll(
- ussOrLocalFileToPdsWarnings.map { ConflictResolution(it.second, it.first).apply { resolveBySkip() } }
- )
+ conflictsResolutions.apply {
+ clear()
+ addAll(ussOrLocalFileToPdsWarnings.map { ConflictResolution(it.second, it.first).apply { resolveBySkip() } })
+ }
}
}
// specific conflicts resolution end
@@ -372,7 +369,7 @@ class ExplorerPasteProvider : PasteProvider {
val operationsToDownload = operations
.filter { operation -> operation.destination !is MFVirtualFile }
- if (operationsToDownload.isNotEmpty()) {
+ if (operationsToDownload.isNotEmpty() && (!isAllConflictsResolvedBySkip(conflictsResolutions, operationsToDownload.size) || operationsToDownload.size == 1)) {
val filesToDownloadUpdated = operationsToDownload.map { operation -> operation.source.name }
val startMessage = "You are going to DOWNLOAD files:"
@@ -470,8 +467,7 @@ class ExplorerPasteProvider : PasteProvider {
"Decide for Each"
),
0,
- AllIcons.General.QuestionDialog,
- null
+ AllIcons.General.QuestionDialog
)
when (choice) {
@@ -504,8 +500,7 @@ class ExplorerPasteProvider : PasteProvider {
"Not Resolvable Conflicts",
arrayOf("Ok"),
0,
- Messages.getErrorIcon(),
- null
+ Messages.getErrorIcon()
)
}
}
@@ -518,6 +513,10 @@ class ExplorerPasteProvider : PasteProvider {
return result
}
+ private fun isAllConflictsResolvedBySkip(conflicts: List, filesToProcessSize: Int) : Boolean {
+ return conflicts.isNotEmpty() && conflicts.map { it.shouldSkip() }.filter { it }.size == conflicts.size && filesToProcessSize == conflicts.size
+ }
+
/**
* Resolve conflicts one by one for case when user select option "Decide for Each".
* @param conflicts Conflict pairs (target - source) that could be resolved using any method.
@@ -623,16 +622,30 @@ class ExplorerPasteProvider : PasteProvider {
return isPastePossibleAndEnabled(dataContext)
}
+ /**
+ * Creates an HTML message from an items list
+ * Message structure:
+ * startMessage
+ * Next, a string is constructed from the items list.
+ * Elements are added to the string until its length does not exceed the limit.
+ * If not all elements were added to the string, then "and more..." is added to the end of the string
+ * finishMessage.
+ * @param startMessage beginning of the message
+ * @param items list of items to display
+ * @param finishMessage end of message
+ * @param limit the maximum allowed length for a converted list of elements.
+ * @return created HTML message
+ */
private fun createHtmlMessageWithItemsList(
- startMessage: String, items: List, finishMessage: String, maxItems: Int = 5
+ startMessage: String, items: List, finishMessage: String, limit: Int = 130
): String {
- val tagP = ""
- val itemsToShow = if (items.size > maxItems) {
- items.subList(0, maxItems).toMutableList().apply { add("more ...") }
- } else {
- items
- }
- val itemsString = "$tagP${itemsToShow.joinToString("
$tagP")}
"
+ val pTag = ""
+ val itemsMerged = items.joinToString(", ")
+ val result = if (itemsMerged.length > limit)
+ itemsMerged.substring(0, limit - 3).plus("...
${pTag}and more...")
+ else
+ itemsMerged
+ val itemsString = pTag.plus(result).plus("")
return "$startMessage\n\n$itemsString\n$finishMessage"
}
}
diff --git a/src/main/kotlin/org/zowe/explorer/explorer/ui/ExplorerTreeNode.kt b/src/main/kotlin/org/zowe/explorer/explorer/ui/ExplorerTreeNode.kt
index 8c88993f6..6bb01d858 100644
--- a/src/main/kotlin/org/zowe/explorer/explorer/ui/ExplorerTreeNode.kt
+++ b/src/main/kotlin/org/zowe/explorer/explorer/ui/ExplorerTreeNode.kt
@@ -112,8 +112,7 @@ abstract class ExplorerTreeNode(
"Error While Opening File ${file.name}",
arrayOf("Ok"),
0,
- AllIcons.General.ErrorDialog,
- null
+ AllIcons.General.ErrorDialog
)
}
} else {
diff --git a/src/main/kotlin/org/zowe/explorer/explorer/ui/ExplorerTreeView.kt b/src/main/kotlin/org/zowe/explorer/explorer/ui/ExplorerTreeView.kt
index bfd3d0168..2b6292ca0 100644
--- a/src/main/kotlin/org/zowe/explorer/explorer/ui/ExplorerTreeView.kt
+++ b/src/main/kotlin/org/zowe/explorer/explorer/ui/ExplorerTreeView.kt
@@ -315,7 +315,13 @@ abstract class ExplorerTreeView> onFetchFailure(query: Q, throwable: Throwable) {
getNodesByQueryAndInvalidate(query)
- explorer.reportThrowable(throwable, project)
+ //The ability to show exceptions for JES Explorer has been disabled.
+ //All messages about exceptions that occur in TreeView components will be displayed using File Explorer.
+ //This was done to avoid duplication of exception messages, since both explorers have a common EventBus and,
+ // accordingly, both receive a message about an exception that occurred in one of them.
+ if (this@ExplorerTreeView is FileExplorerView) {
+ explorer.reportThrowable(throwable, project)
+ }
}
},
disposable = this
diff --git a/src/main/kotlin/org/zowe/explorer/explorer/ui/ExplorerWindowFactory.kt b/src/main/kotlin/org/zowe/explorer/explorer/ui/ExplorerWindowFactory.kt
index 7962561be..9ec2a2d41 100755
--- a/src/main/kotlin/org/zowe/explorer/explorer/ui/ExplorerWindowFactory.kt
+++ b/src/main/kotlin/org/zowe/explorer/explorer/ui/ExplorerWindowFactory.kt
@@ -53,10 +53,8 @@ class ExplorerWindowFactory : ToolWindowFactory, DumbAware {
val contentSynchronizer = dataOpsManager.getContentSynchronizer(file) ?: return
runBackgroundableTask("Synchronizing file ${file.name} with mainframe") { indicator ->
val syncProvider = DocumentedSyncProvider(file)
- runWriteActionInEdtAndWait {
- syncProvider.saveDocument()
- contentSynchronizer.synchronizeWithRemote(syncProvider, indicator)
- }
+ runWriteActionInEdtAndWait { syncProvider.saveDocument() }
+ contentSynchronizer.synchronizeWithRemote(syncProvider, indicator)
}
}
}
diff --git a/src/main/kotlin/org/zowe/explorer/explorer/ui/FileFetchNode.kt b/src/main/kotlin/org/zowe/explorer/explorer/ui/FileFetchNode.kt
index c7c868d05..d9775db90 100644
--- a/src/main/kotlin/org/zowe/explorer/explorer/ui/FileFetchNode.kt
+++ b/src/main/kotlin/org/zowe/explorer/explorer/ui/FileFetchNode.kt
@@ -25,7 +25,6 @@ import org.zowe.explorer.explorer.ExplorerUnit
import org.zowe.explorer.utils.castOrNull
import org.zowe.explorer.utils.locked
import org.zowe.explorer.utils.service
-import java.util.concurrent.atomic.AtomicBoolean
import java.util.concurrent.locks.ReentrantLock
import kotlin.concurrent.withLock
@@ -43,8 +42,6 @@ abstract class FileFetchNode {
return if (attributes is RemoteDatasetAttributes) {
diff --git a/src/main/kotlin/org/zowe/explorer/utils/encodingUtils.kt b/src/main/kotlin/org/zowe/explorer/utils/encodingUtils.kt
index 5594c97ec..2ab0d3e6b 100644
--- a/src/main/kotlin/org/zowe/explorer/utils/encodingUtils.kt
+++ b/src/main/kotlin/org/zowe/explorer/utils/encodingUtils.kt
@@ -17,6 +17,7 @@ import com.intellij.icons.AllIcons
import com.intellij.ide.IdeBundle
import com.intellij.openapi.actionSystem.AnActionEvent
import com.intellij.openapi.actionSystem.DefaultActionGroup
+import com.intellij.openapi.application.runReadAction
import com.intellij.openapi.fileEditor.FileDocumentManager
import com.intellij.openapi.project.DumbAwareAction
import com.intellij.openapi.project.Project
@@ -47,9 +48,9 @@ import javax.swing.Icon
*/
fun saveIn(project: Project?, virtualFile: VirtualFile, charset: Charset) {
val syncProvider = DocumentedSyncProvider(virtualFile, SaveStrategy.default(project))
- syncProvider.saveDocument()
- val bytes = syncProvider.retrieveCurrentContent()
runWriteActionInEdtAndWait {
+ syncProvider.saveDocument()
+ val bytes = syncProvider.retrieveCurrentContent()
changeEncodingTo(virtualFile, charset)
virtualFile.getOutputStream(null).use {
it.write(bytes)
@@ -66,10 +67,8 @@ fun saveIn(project: Project?, virtualFile: VirtualFile, charset: Charset) {
fun reloadIn(project: Project?, virtualFile: VirtualFile, charset: Charset) {
val syncProvider = DocumentedSyncProvider(virtualFile, SaveStrategy.syncOnOpen(project))
val contentSynchronizer = DataOpsManager.instance.getContentSynchronizer(virtualFile)
- runWriteActionInEdtAndWait {
- changeEncodingTo(virtualFile, charset)
- contentSynchronizer?.synchronizeWithRemote(syncProvider)
- }
+ runWriteActionInEdtAndWait { changeEncodingTo(virtualFile, charset) }
+ contentSynchronizer?.synchronizeWithRemote(syncProvider)
}
/** Changes the file encoding to the specified one. */
@@ -125,7 +124,7 @@ fun inspectSafeEncodingChange(virtualFile: VirtualFile, charset: Charset): Encod
val fileNotSynced = contentSynchronizer?.isFileUploadNeeded(syncProvider) == true
val text = syncProvider.getDocument()?.text
?: throw IllegalArgumentException("Cannot get document text")
- val bytes = if (fileNotSynced) syncProvider.retrieveCurrentContent()
+ val bytes = if (fileNotSynced) runReadAction { syncProvider.retrieveCurrentContent() }
else contentSynchronizer?.successfulContentStorage(syncProvider)
?: throw IllegalArgumentException("Cannot get content bytes")
val safeToReload = isSafeToReloadIn(virtualFile, text, bytes, charset)
diff --git a/src/main/kotlin/org/zowe/explorer/utils/validationFunctions.kt b/src/main/kotlin/org/zowe/explorer/utils/validationFunctions.kt
index 597b55f4e..e948e6216 100644
--- a/src/main/kotlin/org/zowe/explorer/utils/validationFunctions.kt
+++ b/src/main/kotlin/org/zowe/explorer/utils/validationFunctions.kt
@@ -49,6 +49,14 @@ private val volserRegex = Regex("[A-Za-z0-9]{1,6}")
private val firstLetterRegex = Regex("[A-Z@\$#a-z]")
private val memberRegex = Regex("[A-Z@$#a-z][A-Z@#\$a-z0-9]{0,7}")
+/**
+ * Validate text field for a match with the previous value
+ * @param prev of the current node
+ * @param component the component containing the invalid data
+ */
+fun validateForTheSameValue(prev: String?, component: JTextField): ValidationInfo? {
+ return if (component.text == prev) ValidationInfo("Field value matches the previous one", component) else null
+}
/**
* Validate text field for blank value
diff --git a/src/main/kotlin/org/zowe/explorer/vfs/MFVirtualFileSystemModel.kt b/src/main/kotlin/org/zowe/explorer/vfs/MFVirtualFileSystemModel.kt
index cf8115605..94c506782 100755
--- a/src/main/kotlin/org/zowe/explorer/vfs/MFVirtualFileSystemModel.kt
+++ b/src/main/kotlin/org/zowe/explorer/vfs/MFVirtualFileSystemModel.kt
@@ -311,13 +311,13 @@ class MFVirtualFileSystemModel {
@Throws(IOException::class)
fun renameFile(requestor: Any?, vFile: MFVirtualFile, newName: String) {
val event = listOf(VFilePropertyChangeEvent(requestor, vFile, VirtualFile.PROP_NAME, vFile.name, newName, false))
- sendMFVfsChangesTopic().before(event)
+ sendVfsChangesTopic().before(event)
vFile.validReadLock {
if (vFile.filenameInternal != newName) {
vFile.filenameInternal = newName
}
}
- sendMFVfsChangesTopic().after(event)
+ sendVfsChangesTopic().after(event)
}
@Throws(IOException::class)
diff --git a/src/test/kotlin/org/zowe/explorer/config/ConfigTestSpec.kt b/src/test/kotlin/org/zowe/explorer/config/ConfigTestSpec.kt
index f3bea8222..406a67f25 100644
--- a/src/test/kotlin/org/zowe/explorer/config/ConfigTestSpec.kt
+++ b/src/test/kotlin/org/zowe/explorer/config/ConfigTestSpec.kt
@@ -237,6 +237,73 @@ class ConfigTestSpec : WithApplicationShouldSpec({
assertSoftly { actual shouldBe "ZOSMFAD" }
}
+
+ should("return empty owner if TSO request returns empty data") {
+ dataOpsManagerService.testInstance = object : TestDataOpsManagerImpl(explorerMock.componentManager) {
+ override fun performOperation(operation: Operation, progressIndicator: ProgressIndicator): R {
+ val tsoResponse = TsoResponse(
+ servletKey = "servletKey",
+ tsoData = listOf(TsoData())
+ )
+ if ((operation as TsoOperation).mode == TsoOperationMode.SEND_MESSAGE) {
+ tsoResponse.tsoData = listOf(
+ TsoData(tsoMessage = MessageType("", ""))
+ )
+ }
+ @Suppress("UNCHECKED_CAST")
+ return tsoResponse as R
+ }
+ }
+
+ val actual = whoAmI(connectionConfig)
+
+ assertSoftly { actual shouldBe "" }
+ }
+
+ should("return empty owner if TSO request returns READY") {
+ dataOpsManagerService.testInstance = object : TestDataOpsManagerImpl(explorerMock.componentManager) {
+ override fun performOperation(operation: Operation, progressIndicator: ProgressIndicator): R {
+ val tsoResponse = TsoResponse(
+ servletKey = "servletKey",
+ tsoData = listOf(TsoData())
+ )
+ if ((operation as TsoOperation).mode == TsoOperationMode.SEND_MESSAGE) {
+ tsoResponse.tsoData = listOf(
+ TsoData(tsoMessage = MessageType("", "READY "))
+ )
+ }
+ @Suppress("UNCHECKED_CAST")
+ return tsoResponse as R
+ }
+ }
+
+ val actual = whoAmI(connectionConfig)
+
+ assertSoftly { actual shouldBe "" }
+ }
+
+ should("return empty owner if TSO request returns error message in TSO data") {
+ dataOpsManagerService.testInstance = object : TestDataOpsManagerImpl(explorerMock.componentManager) {
+ override fun performOperation(operation: Operation, progressIndicator: ProgressIndicator): R {
+ val tsoResponse = TsoResponse(
+ servletKey = "servletKey",
+ tsoData = listOf(TsoData())
+ )
+ if ((operation as TsoOperation).mode == TsoOperationMode.SEND_MESSAGE) {
+ tsoResponse.tsoData = listOf(
+ TsoData(tsoMessage = MessageType("", "OSHELL RC = 65210"))
+ )
+ }
+ @Suppress("UNCHECKED_CAST")
+ return tsoResponse as R
+ }
+ }
+
+ val actual = whoAmI(connectionConfig)
+
+ assertSoftly { actual shouldBe "" }
+ }
+
should("do not get the owner by TSO request if servlet key is null") {
dataOpsManagerService.testInstance = object : TestDataOpsManagerImpl(explorerMock.componentManager) {
override fun performOperation(operation: Operation, progressIndicator: ProgressIndicator): R {
diff --git a/src/test/kotlin/org/zowe/explorer/explorer/ui/ExplorerPasteProviderTestSpec.kt b/src/test/kotlin/org/zowe/explorer/explorer/ui/ExplorerPasteProviderTestSpec.kt
index d13cdc593..9a9204b0a 100644
--- a/src/test/kotlin/org/zowe/explorer/explorer/ui/ExplorerPasteProviderTestSpec.kt
+++ b/src/test/kotlin/org/zowe/explorer/explorer/ui/ExplorerPasteProviderTestSpec.kt
@@ -459,12 +459,12 @@ class ExplorerPasteProviderTestSpec : WithApplicationShouldSpec({
isPastePerformed = false
val showDialogMock: (
- Project?, String, String, Array, Int, Icon?, DialogWrapper.DoNotAskOption?
+ Project?, String, String, Array, Int, Icon?
) -> Int = Messages::showDialog
mockkStatic(showDialogMock as KFunction<*>)
every {
showDialogMock(
- any(), any(), any(), any>(), any(), any() as Icon?, any()
+ any(), any(), any(), any>(), any(), any() as Icon?
)
} answers {
isShowDialogCalled = true
@@ -580,12 +580,12 @@ class ExplorerPasteProviderTestSpec : WithApplicationShouldSpec({
}
val showDialogMock: (
- Project?, String, String, Array, Int, Icon?, DialogWrapper.DoNotAskOption?
+ Project?, String, String, Array, Int, Icon?
) -> Int = Messages::showDialog
mockkStatic(showDialogMock as KFunction<*>)
every {
showDialogMock(
- any(), any(), any(), any>(), any(), any() as Icon?, any()
+ any(), any(), any(), any>(), any(), any() as Icon?
)
} answers {
isShowDialogCalled = true
@@ -602,12 +602,12 @@ class ExplorerPasteProviderTestSpec : WithApplicationShouldSpec({
should("return if unrecognized dialog message") {
isPastePerformed = true
val showDialogSpecificMock: (
- Project?, String, String, Array, Int, Icon?, DialogWrapper.DoNotAskOption?
+ Project?, String, String, Array, Int, Icon?
) -> Int = Messages::showDialog
mockkStatic(showDialogSpecificMock as KFunction<*>)
every {
showDialogSpecificMock(
- any(), any(), any(), any>(), any(), any() as Icon?, any()
+ any(), any(), any(), any>(), any(), any() as Icon?
)
} answers {
isPastePerformed = false
@@ -689,12 +689,12 @@ class ExplorerPasteProviderTestSpec : WithApplicationShouldSpec({
every { mockedFileExplorerView.isCut } returns AtomicBoolean(false)
val showDialogSpecificMock: (
- Project?, String, String, Array, Int, Icon?, DialogWrapper.DoNotAskOption?
+ Project?, String, String, Array, Int, Icon?
) -> Int = Messages::showDialog
mockkStatic(showDialogSpecificMock as KFunction<*>)
every {
showDialogSpecificMock(
- any(), any(), any(), any>(), any(), any() as Icon?, any()
+ any(), any(), any(), any>(), any(), any() as Icon?
)
} answers {
isShowYesNoDialogCalled = true
diff --git a/src/test/kotlin/org/zowe/explorer/explorer/ui/UssFileNodeTestSpec.kt b/src/test/kotlin/org/zowe/explorer/explorer/ui/UssFileNodeTestSpec.kt
index 79127c739..566c494b2 100644
--- a/src/test/kotlin/org/zowe/explorer/explorer/ui/UssFileNodeTestSpec.kt
+++ b/src/test/kotlin/org/zowe/explorer/explorer/ui/UssFileNodeTestSpec.kt
@@ -208,11 +208,11 @@ class UssFileNodeTestSpec : WithApplicationShouldSpec({
var isErrorMessageInDialogCalled = false
val showDialogSpecificMock: (
- Project?, String, String, Array, Int, Icon?, DialogWrapper.DoNotAskOption?
+ Project?, String, String, Array, Int, Icon?
) -> Int = Messages::showDialog
mockkStatic(showDialogSpecificMock as KFunction<*>)
every {
- showDialogSpecificMock(any(), any(), any(), any>(), any(), any(), any())
+ showDialogSpecificMock(any(), any(), any(), any>(), any(), any() as Icon?)
} answers {
isErrorMessageInDialogCalled = true
1