@@ -17,6 +17,8 @@ import eu.ibagroup.formainframe.dataops.DataOpsManager
1717import eu.ibagroup.formainframe.dataops.attributes.RemoteUssAttributes
1818import eu.ibagroup.formainframe.dataops.attributes.USS_DELIMITER
1919import eu.ibagroup.formainframe.dataops.exceptions.CallException
20+ import eu.ibagroup.formainframe.dataops.operations.DeleteOperation
21+ import eu.ibagroup.formainframe.dataops.operations.DeleteOperationRunner
2022import eu.ibagroup.formainframe.dataops.operations.OperationRunner
2123import eu.ibagroup.formainframe.dataops.operations.OperationRunnerFactory
2224import eu.ibagroup.formainframe.utils.cancelByIndicator
@@ -25,7 +27,6 @@ import eu.ibagroup.formainframe.utils.log
2527import org.zowe.kotlinsdk.CopyDataUSS
2628import org.zowe.kotlinsdk.DataAPI
2729import org.zowe.kotlinsdk.FilePath
28- import org.zowe.kotlinsdk.MoveUssFile
2930import retrofit2.Call
3031import retrofit2.Response
3132
@@ -43,6 +44,7 @@ class UssToUssFileMoverFactory : OperationRunnerFactory {
4344 * Implements copying of uss file to uss directory inside 1 system
4445 */
4546class UssToUssFileMover (private val dataOpsManager : DataOpsManager ) : AbstractFileMover() {
47+
4648 override fun canRun (operation : MoveCopyOperation ): Boolean {
4749 return operation.sourceAttributes is RemoteUssAttributes
4850 && operation.destinationAttributes is RemoteUssAttributes
@@ -57,30 +59,48 @@ class UssToUssFileMover(private val dataOpsManager: DataOpsManager) : AbstractFi
5759 * Proceeds move/copy of uss file to uss directory
5860 * @param connectionConfig connection configuration of system inside which to copy file
5961 * @param operation requested operation
60- * @param progressIndicator indicator that will show progress of copying/moving in UI
6162 */
6263 private fun makeCall (
6364 connectionConfig : ConnectionConfig ,
64- operation : MoveCopyOperation ,
65- progressIndicator : ProgressIndicator
66- ): Triple <Call <Void >, String, String> {
65+ operation : MoveCopyOperation
66+ ): Triple <Pair <Call <Void >, () -> Unit>, String, String> {
6767 val sourceAttributes = (operation.sourceAttributes as RemoteUssAttributes )
68- val destinationAttributes = (operation.destinationAttributes as RemoteUssAttributes )
6968 val from = sourceAttributes.path
70- val to = destinationAttributes.path + USS_DELIMITER + (operation.newName ? : sourceAttributes.name)
71- val api = api<DataAPI >(connectionConfig)
72- val call = if (operation.isMove) {
73- api.moveUssFile(
74- authorizationToken = connectionConfig.authToken,
75- body = MoveUssFile (
76- from = from
77- ),
78- filePath = FilePath (
79- path = to
80- )
81- )
82- } else {
83- api.copyUssFile(
69+ val to = computeUssDestination(operation)
70+ val call = if (operation.isMove)
71+ buildMoveCall(connectionConfig, operation, from, to)
72+ else
73+ buildCopyCall(connectionConfig, operation, from, to)
74+ return Triple (call, from, to)
75+ }
76+
77+ /* *
78+ * Function builds a Move call and Delete source callback after moving is performed
79+ * @return Pair of Move call and its delete source file callback
80+ */
81+ private fun buildMoveCall (
82+ connectionConfig : ConnectionConfig ,
83+ operation : MoveCopyOperation ,
84+ from : String ,
85+ to : String )
86+ : Pair <Call <Void >, () -> Unit > {
87+ val copyCall = buildCopyCall(connectionConfig, operation, from, to).first
88+ val deleteSourceCallback = buildDeleteSourceCallback(operation)
89+ return Pair (copyCall, deleteSourceCallback)
90+ }
91+
92+ /* *
93+ * Function builds a Copy call
94+ * @return Pair of Copy call and empty callback function to execute after Copy is performed
95+ */
96+ private fun buildCopyCall (
97+ connectionConfig : ConnectionConfig ,
98+ operation : MoveCopyOperation ,
99+ from : String ,
100+ to : String )
101+ : Pair <Call <Void >, () -> Unit > {
102+ return Pair (
103+ api<DataAPI >(connectionConfig).copyUssFile(
84104 authorizationToken = connectionConfig.authToken,
85105 body = CopyDataUSS .CopyFromFileOrDir (
86106 from = from,
@@ -93,8 +113,53 @@ class UssToUssFileMover(private val dataOpsManager: DataOpsManager) : AbstractFi
93113 path = to
94114 )
95115 )
116+ ) {}
117+ }
118+
119+ /* *
120+ * Function builds a Delete callback which will be executed after successful Move is performed
121+ * @return delete callback
122+ */
123+ private fun buildDeleteSourceCallback (operation : MoveCopyOperation ): () -> Unit {
124+ return {
125+ val sourceAttributes = operation.sourceAttributes as RemoteUssAttributes
126+ val deleteOperation = DeleteOperation (operation.source, sourceAttributes)
127+ DeleteOperationRunner (dataOpsManager).run (deleteOperation)
128+ }
129+ }
130+
131+ /* *
132+ * Function is used to determine the correct USS destination for Move/Copy operation
133+ * The possible list of destinations are:
134+ *
135+ * Copying:
136+ * 1. Directory -> Directory without(with) conflict: Destination would be <ROOT_PATH>
137+ * 2. Directory -> Directory with conflict, but "Use new name" option was pressed: Destination would be <ROOT_PATH>/<NEW_DIR_NAME>
138+ * 3. File -> Directory with conflict: Destination would be <ROOT_PATH>/<FILE_NEW_NAME>
139+ * 4. File -> Directory without conflict: Destination would be <ROOT_PATH>/<SOURCE_FILE_NAME>
140+ *
141+ * Moving:
142+ * 1. Directory -> Directory without(with) conflict: Destination would be <ROOT_PATH>
143+ * 2. Directory -> Directory with conflict and "Use new name" is pressed: Destination would be <ROOT_PATH>/<NEW_DIR_NAME>
144+ * 3. File -> Directory the same behavior as for Copying
145+ *
146+ * * example: mv(cp) -Rf /u/<USER>/test /u/<USER>/destination
147+ * * (if test is present under destination all files and subdirs from /u/<USER>/test will be copied/moved
148+ * * and overwritten in /u/<USER>/destination/test, otherwise test would be copied/moved to /u/<USER>/destination/test)
149+ * * If operation is Move, the source would be deleted afterward
150+ *
151+ * @return target destination in String format
152+ */
153+ private fun computeUssDestination (operation : MoveCopyOperation ) : String {
154+ val destinationRootPath = (operation.destinationAttributes as RemoteUssAttributes ).path
155+ val destinationNewName = operation.newName
156+ val destinationNewNameWithDelimiter = USS_DELIMITER + operation.newName
157+ // Copying or Moving USS directory
158+ return if (operation.source.isDirectory && operation.destination.isDirectory) {
159+ destinationRootPath + if (destinationNewName != null ) destinationNewNameWithDelimiter else " "
96160 }
97- return Triple (call.cancelByIndicator(progressIndicator), from, to)
161+ // Copying or Moving USS file
162+ else destinationRootPath + USS_DELIMITER + (operation.newName ? : operation.sourceAttributes?.name)
98163 }
99164
100165 /* *
@@ -106,11 +171,14 @@ class UssToUssFileMover(private val dataOpsManager: DataOpsManager) : AbstractFi
106171 var throwable: Throwable ? = null
107172 for ((requester, _) in operation.commonUrls(dataOpsManager)) {
108173 try {
109- val (call, from, to) = makeCall(requester.connectionConfig, operation, progressIndicator )
174+ val (call, from, to) = makeCall(requester.connectionConfig, operation)
110175 val operationName = if (operation.isMove) " move" else " copy"
111- val response: Response <Void > = call.execute()
176+ val response: Response <Void > = call.first.cancelByIndicator(progressIndicator). execute()
112177 if (! response.isSuccessful) {
113178 throwable = CallException (response, " Cannot $operationName $from to $to " )
179+ } else {
180+ // Call the built early callback for source file/dir deletion (always empty callback for Copy)
181+ call.second.invoke()
114182 }
115183 break
116184 } catch (t: Throwable ) {
0 commit comments