Skip to content

Commit 59df16d

Browse files
committed
Merge branch 'private-release/v2.0.0' into public-release/v2.0.0
2 parents 02acfd1 + b0320b1 commit 59df16d

43 files changed

Lines changed: 507 additions & 351 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ All notable changes to the Zowe IntelliJ Plugin will be documented in this file.
2929
* Feature: "Rate us" notification added ([577b81c2](https://github.com/zowe/zowe-explorer-intellij/commit/577b81c2))
3030
* Feature: "reportThrowable" replaced with "notifyError" ([577b81c2](https://github.com/zowe/zowe-explorer-intellij/commit/577b81c2))
3131
* Feature: Correct alignment for fields in working set dialog ([745143cc](https://github.com/zowe/zowe-explorer-intellij/commit/745143cc))
32+
* Feature: Credentials are nullable now ([b643d2ff](https://github.com/zowe/zowe-explorer-intellij/commit/b643d2ff))
3233

3334
### Bugfixes
3435

src/main/kotlin/eu/ibagroup/formainframe/config/connect/CredentialService.kt

Lines changed: 46 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,12 @@ package eu.ibagroup.formainframe.config.connect
1616

1717
import com.intellij.openapi.components.service
1818
import com.intellij.util.messages.Topic
19-
import eu.ibagroup.formainframe.dataops.exceptions.CredentialsNotFoundForConnection
19+
import eu.ibagroup.formainframe.dataops.exceptions.CredentialsNotFoundForConnectionException
2020
import eu.ibagroup.formainframe.utils.runTask
2121
import okhttp3.Credentials
2222

23+
const val USER_OR_OWNER_SYMBOLS_MAX_SIZE: Int = 8
24+
2325
/**
2426
* Interface which represents objects that track changes in credentials
2527
*/
@@ -41,8 +43,48 @@ val CREDENTIALS_CHANGED = Topic.create("credentialChanges", CredentialsListener:
4143
interface CredentialService {
4244

4345
companion object {
46+
4447
@JvmStatic
4548
fun getService(): CredentialService = service()
49+
50+
/**
51+
* Returns a username of a particular connection config or throws the [CredentialsNotFoundForConnectionException]
52+
* @param connectionConfig connection config instance to search username for
53+
* @return the username of the connection config
54+
*/
55+
@JvmStatic
56+
fun <ConnectionConfig : ConnectionConfigBase> getUsername(connectionConfig: ConnectionConfig) =
57+
getService().getUsernameByKey(connectionConfig.uuid)
58+
?: throw CredentialsNotFoundForConnectionException(connectionConfig)
59+
60+
/**
61+
* Returns a password of a particular connection config or throws the [CredentialsNotFoundForConnectionException]
62+
* @param connectionConfig connection config instance to search password for
63+
* @return the password of the connection config
64+
*/
65+
@JvmStatic
66+
fun <ConnectionConfig : ConnectionConfigBase> getPassword(connectionConfig: ConnectionConfig) =
67+
getService().getPasswordByKey(connectionConfig.uuid)
68+
?: throw CredentialsNotFoundForConnectionException(connectionConfig)
69+
70+
/**
71+
* Returns owner of particular connection config if the owner field is not empty or conforms
72+
* the [USER_OR_OWNER_SYMBOLS_MAX_SIZE] in length, or the username otherwise.
73+
* If whoAmI function failed for some reason it could contain empty "" or error string inside owner variable.
74+
* If it is such case, then it returns username of the connection config.
75+
* @param connectionConfig connection config instance to get owner from
76+
* @return owner or username of the connection config if the owner is incorrect or missing
77+
*/
78+
@JvmStatic
79+
fun getOwner(connectionConfig: ConnectionConfig): String {
80+
val possibleOwner = connectionConfig.owner
81+
return if (possibleOwner.isNotEmpty() && possibleOwner.chars().count() <= USER_OR_OWNER_SYMBOLS_MAX_SIZE) {
82+
possibleOwner
83+
} else {
84+
getUsername(connectionConfig)
85+
}
86+
}
87+
4688
}
4789

4890
/**
@@ -75,31 +117,9 @@ interface CredentialService {
75117

76118
}
77119

78-
/**
79-
* Returns username of particular connection config.
80-
* @param connectionConfig connection config instance.
81-
* @return username of connection config.
82-
*/
83-
fun <Connection : ConnectionConfigBase> getUsername(connectionConfig: Connection): String {
84-
return CredentialService.getService().getUsernameByKey(connectionConfig.uuid)
85-
?: throw CredentialsNotFoundForConnection(
86-
connectionConfig
87-
)
88-
}
89-
90-
/**
91-
* Returns password of particular connection config.
92-
* @param connectionConfig connection config instance.
93-
* @return password of particular connection config.
94-
*/
95-
fun <Connection : ConnectionConfigBase> getPassword(connectionConfig: Connection): String {
96-
return CredentialService.getService().getPasswordByKey(connectionConfig.uuid)
97-
?: throw CredentialsNotFoundForConnection(
98-
connectionConfig
99-
)
100-
}
101-
102120
val ConnectionConfig.authToken: String
103121
get() = runTask("Retrieving information for auth token") {
104-
Credentials.basic(getUsername(this), getPassword(this))
122+
val username = CredentialService.getUsername(this)
123+
val password = CredentialService.getPassword(this)
124+
Credentials.basic(username, password)
105125
}

src/main/kotlin/eu/ibagroup/formainframe/config/connect/connectUtils.kt

Lines changed: 21 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -25,15 +25,10 @@ import eu.ibagroup.formainframe.dataops.operations.TsoOperationMode
2525
import eu.ibagroup.formainframe.tso.TSOWindowFactory
2626
import eu.ibagroup.formainframe.tso.config.TSOConfigWrapper
2727
import eu.ibagroup.formainframe.tso.config.ui.TSOSessionDialogState
28-
import org.zowe.kotlinsdk.TsoApi
29-
import org.zowe.kotlinsdk.TsoCmdRequestBody
30-
import org.zowe.kotlinsdk.TsoCmdResult
31-
import org.zowe.kotlinsdk.TsoCmdState
32-
import org.zowe.kotlinsdk.TsoData
28+
import org.zowe.kotlinsdk.*
3329
import org.zowe.kotlinsdk.annotations.ZVersion
3430

35-
const val USER_OR_OWNER_SYMBOLS_MAX_SIZE: Int = 8
36-
const val WHO_AM_I: String = "oshell whoami"
31+
const val WHO_AM_I_CMD: String = "oshell whoami"
3732
val LOGGER = logger<ConnectionDialog>()
3833

3934
/**
@@ -67,7 +62,7 @@ fun whoAmI(connectionConfig: ConnectionConfig): String? {
6762
mode = TsoOperationMode.SEND_MESSAGE,
6863
messageType = MessageType.TSO_RESPONSE,
6964
messageData = MessageData.DATA_DATA,
70-
message = WHO_AM_I
65+
message = WHO_AM_I_CMD
7166
)
7267
)
7368
queuedMessages.addAll(sendCommandResponse.tsoData)
@@ -111,7 +106,7 @@ fun executeWhoAmIEnhanced(connectionConfig: ConnectionConfig): String? {
111106
val newTsoResponse = api<TsoApi>(connectionConfig).executeTsoCommand(
112107
authorizationToken = connectionConfig.authToken,
113108
body = TsoCmdRequestBody(
114-
tsoCmd = WHO_AM_I,
109+
tsoCmd = WHO_AM_I_CMD,
115110
cmdState = TsoCmdState.STATELESS
116111
)
117112
).execute()
@@ -135,12 +130,15 @@ fun executeWhoAmIEnhanced(connectionConfig: ConnectionConfig): String? {
135130
*/
136131
fun tryToExtractRealOwner(tsoData: List<TsoData>): String {
137132
val emptyOwner = ""
138-
val filteredData = tsoData.filter {
139-
val tsoMessage = it.tsoMessage ?: return@filter false
140-
val messageData = tsoMessage.data?.trim() ?: return@filter false
141-
messageData.isNotEmpty() && !messageData.contains("READY") && messageData.chars()
142-
.count() <= USER_OR_OWNER_SYMBOLS_MAX_SIZE
143-
}.mapNotNull { it.tsoMessage?.data?.trim() }
133+
val filteredData = tsoData
134+
.filter {
135+
val tsoMessage = it.tsoMessage ?: return@filter false
136+
val messageData = tsoMessage.data?.trim() ?: return@filter false
137+
messageData.isNotEmpty()
138+
&& !messageData.contains("READY")
139+
&& messageData.chars().count() <= USER_OR_OWNER_SYMBOLS_MAX_SIZE
140+
}
141+
.mapNotNull { it.tsoMessage?.data?.trim() }
144142

145143
return if (filteredData.isNotEmpty()) filteredData[0] else emptyOwner
146144
}
@@ -152,33 +150,14 @@ fun tryToExtractRealOwner(tsoData: List<TsoData>): String {
152150
*/
153151
fun tryToExtractRealOwnerEnhanced(tsoData: List<TsoCmdResult>): String {
154152
val emptyOwner = ""
155-
val filteredData = tsoData.filter {
156-
val tsoMessage = it.message?.trim() ?: return@filter false
157-
tsoMessage.isNotEmpty() && !tsoMessage.contains("READY") && tsoMessage.chars()
158-
.count() <= USER_OR_OWNER_SYMBOLS_MAX_SIZE
159-
}.mapNotNull { it.message?.trim() }
153+
val filteredData = tsoData
154+
.filter {
155+
val tsoMessage = it.message?.trim() ?: return@filter false
156+
tsoMessage.isNotEmpty()
157+
&& !tsoMessage.contains("READY")
158+
&& tsoMessage.chars().count() <= USER_OR_OWNER_SYMBOLS_MAX_SIZE
159+
}
160+
.mapNotNull { it.message?.trim() }
160161

161162
return if (filteredData.isNotEmpty()) filteredData[0] else emptyOwner
162163
}
163-
164-
/**
165-
* Returns owner of particular connection config if it is not empty, or the username otherwise.
166-
* @param connectionConfig connection config instance.
167-
* @return owner of connection config.
168-
*/
169-
fun getOwner(connectionConfig: ConnectionConfig): String {
170-
return connectionConfig.owner.ifEmpty { getUsername(connectionConfig) }
171-
}
172-
173-
/**
174-
* Function tries to extract owner from the connection config.
175-
* If whoAmI function failed for some reason it could contain empty "" or error string inside owner variable.
176-
* If it is such a case then return username of the connection config.
177-
* @return username of the connection config or extracted owner
178-
*/
179-
fun tryToExtractOwnerFromConfig(connectionConfig: ConnectionConfig): String {
180-
val possibleOwner = connectionConfig.owner
181-
return if (possibleOwner.isEmpty() || possibleOwner.chars().count() > USER_OR_OWNER_SYMBOLS_MAX_SIZE)
182-
getUsername(connectionConfig)
183-
else possibleOwner
184-
}

src/main/kotlin/eu/ibagroup/formainframe/config/connect/ui/ConnectionUsernameColumn.kt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
package eu.ibagroup.formainframe.config.connect.ui
1616

1717
import com.intellij.util.ui.ColumnInfo
18+
import eu.ibagroup.formainframe.config.connect.ui.renderer.UsernameColumnRenderer
19+
import javax.swing.table.TableCellRenderer
1820

1921
/**
2022
* Class which represents column of username in GUI
@@ -40,4 +42,8 @@ class ConnectionUsernameColumn<ConnectionState : ConnectionDialogStateBase<*>>
4042
item.username = value
4143
}
4244

45+
override fun getRenderer(o: ConnectionState): TableCellRenderer {
46+
return UsernameColumnRenderer()
47+
}
48+
4349
}
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
/*
2+
* Copyright (c) 2024 IBA Group.
3+
*
4+
* This program and the accompanying materials are made available under the terms of the
5+
* Eclipse Public License v2.0 which accompanies this distribution, and is available at
6+
* https://www.eclipse.org/legal/epl-v20.html
7+
*
8+
* SPDX-License-Identifier: EPL-2.0
9+
*
10+
* Contributors:
11+
* IBA Group
12+
* Zowe Community
13+
*/
14+
15+
package eu.ibagroup.formainframe.config.connect.ui.renderer
16+
17+
import com.intellij.icons.AllIcons
18+
import com.intellij.util.ui.table.IconTableCellRenderer
19+
import eu.ibagroup.formainframe.common.message
20+
import java.awt.Component
21+
import javax.swing.Icon
22+
import javax.swing.JTable
23+
24+
const val USERNAME_NOT_PRESENT_WARNING_TOOLTIP_TEXT =
25+
"Username for the connection is not found. Try fixing it by editing the connection"
26+
const val NO_CONNECTION_ERROR_TOOLTIP_TEXT =
27+
"Connection is not found for the element"
28+
29+
/**
30+
* Custom renderer class for the username column in the connections table view. Provides functionality to render
31+
* a warning icon with a warning text about the username column
32+
*/
33+
class UsernameColumnRenderer : IconTableCellRenderer<String>() {
34+
35+
/**
36+
* Function returns a warning icon if the username is empty or null otherwise
37+
* @param value the username cell value to check
38+
* @param table the table to render the icon in
39+
* @param row the row to render the icon in
40+
* @return the icon or null, depending on the check result
41+
*/
42+
override fun getIcon(value: String, table: JTable, row: Int): Icon? {
43+
return when {
44+
value.isEmpty() -> {
45+
AllIcons.General.Warning
46+
}
47+
48+
value == message("configurable.ws.tables.ws.username.error.empty") -> {
49+
AllIcons.General.Error
50+
}
51+
52+
else -> {
53+
null
54+
}
55+
}
56+
}
57+
58+
/**
59+
* Function returns a component which renders the username cell
60+
* @param table the table to render the cell in
61+
* @param value the username cell value
62+
* @param selected a parameter to check whether the cell is selected
63+
* @param focus a parameter to check whether the cell is focused
64+
* @param row the row to render the cell in
65+
* @param column the column to render the cell in
66+
* @return the actual component with a custom renderer
67+
*/
68+
override fun getTableCellRendererComponent(
69+
table: JTable?,
70+
value: Any?,
71+
selected: Boolean,
72+
focus: Boolean,
73+
row: Int,
74+
column: Int
75+
): Component {
76+
super.getTableCellRendererComponent(table, value, selected, focus, row, column)
77+
toolTipText = when (icon) {
78+
AllIcons.General.Warning -> {
79+
USERNAME_NOT_PRESENT_WARNING_TOOLTIP_TEXT
80+
}
81+
82+
AllIcons.General.Error -> {
83+
NO_CONNECTION_ERROR_TOOLTIP_TEXT
84+
}
85+
86+
else -> {
87+
message("configurable.ws.tables.ws.username.tooltip")
88+
}
89+
}
90+
return this
91+
}
92+
93+
}

src/main/kotlin/eu/ibagroup/formainframe/config/connect/ui/zosmf/ConnectionDialog.kt

Lines changed: 14 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -30,39 +30,27 @@ import com.intellij.openapi.ui.popup.JBPopupFactory
3030
import com.intellij.ui.awt.RelativePoint
3131
import com.intellij.ui.components.JBCheckBox
3232
import com.intellij.ui.components.JBTextField
33-
import com.intellij.ui.dsl.builder.AlignX
34-
import com.intellij.ui.dsl.builder.Cell
35-
import com.intellij.ui.dsl.builder.bindItem
36-
import com.intellij.ui.dsl.builder.bindSelected
37-
import com.intellij.ui.dsl.builder.bindText
38-
import com.intellij.ui.dsl.builder.panel
39-
import com.intellij.ui.dsl.builder.toNullableProperty
33+
import com.intellij.ui.dsl.builder.*
4034
import eu.ibagroup.formainframe.common.message
4135
import eu.ibagroup.formainframe.common.ui.DialogMode
4236
import eu.ibagroup.formainframe.common.ui.StatefulDialog
4337
import eu.ibagroup.formainframe.common.ui.showUntilDone
4438
import eu.ibagroup.formainframe.config.ConfigService
4539
import eu.ibagroup.formainframe.config.connect.ConnectionConfig
4640
import eu.ibagroup.formainframe.config.connect.CredentialService
47-
import eu.ibagroup.formainframe.config.connect.getPassword
48-
import eu.ibagroup.formainframe.config.connect.getUsername
4941
import eu.ibagroup.formainframe.config.connect.ui.ChangePasswordDialog
5042
import eu.ibagroup.formainframe.config.connect.ui.ChangePasswordDialogState
5143
import eu.ibagroup.formainframe.config.connect.whoAmI
5244
import eu.ibagroup.formainframe.dataops.DataOpsManager
45+
import eu.ibagroup.formainframe.dataops.exceptions.CredentialsNotFoundForConnectionException
5346
import eu.ibagroup.formainframe.dataops.operations.ChangePasswordOperation
5447
import eu.ibagroup.formainframe.dataops.operations.InfoOperation
5548
import eu.ibagroup.formainframe.dataops.operations.ZOSInfoOperation
5649
import eu.ibagroup.formainframe.explorer.EXPLORER_NOTIFICATION_GROUP_ID
50+
import eu.ibagroup.formainframe.utils.*
5751
import eu.ibagroup.formainframe.utils.crudable.Crudable
5852
import eu.ibagroup.formainframe.utils.crudable.find
5953
import eu.ibagroup.formainframe.utils.crudable.getAll
60-
import eu.ibagroup.formainframe.utils.removeTrailingSlashes
61-
import eu.ibagroup.formainframe.utils.runIfTrue
62-
import eu.ibagroup.formainframe.utils.runTask
63-
import eu.ibagroup.formainframe.utils.validateConnectionName
64-
import eu.ibagroup.formainframe.utils.validateForBlank
65-
import eu.ibagroup.formainframe.utils.validateZosmfUrl
6654
import org.zowe.kotlinsdk.ChangePassword
6755
import org.zowe.kotlinsdk.annotations.ZVersion
6856
import java.awt.Component
@@ -470,17 +458,24 @@ class ConnectionDialog(
470458
override fun doCancelAction() {
471459
super.doCancelAction()
472460
if (state.mode == DialogMode.UPDATE) {
461+
var username = lastSuccessfulState.username
462+
var password = lastSuccessfulState.password
463+
try {
464+
username = CredentialService.getUsername(lastSuccessfulState.connectionConfig)
465+
password = CredentialService.getPassword(lastSuccessfulState.connectionConfig)
466+
} catch (_: CredentialsNotFoundForConnectionException) {
467+
}
473468
state.connectionName = lastSuccessfulState.connectionName
474469
state.connectionUrl = lastSuccessfulState.connectionUrl
475-
state.username = getUsername(lastSuccessfulState.connectionConfig)
476-
state.password = getPassword(lastSuccessfulState.connectionConfig)
470+
state.username = username
471+
state.password = password
477472
state.isAllowSsl = lastSuccessfulState.isAllowSsl
478473
state.zVersion = lastSuccessfulState.zVersion
479474
runBackgroundableTask("Setting credentials", project, false) {
480475
CredentialService.getService().setCredentials(
481476
connectionConfigUuid = lastSuccessfulState.connectionUuid,
482-
username = getUsername(lastSuccessfulState.connectionConfig),
483-
password = getPassword(lastSuccessfulState.connectionConfig)
477+
username = username,
478+
password = password
484479
)
485480
}
486481
}

0 commit comments

Comments
 (0)