Skip to content

Commit acbae6b

Browse files
Refactor account ID handling to use Serializable type for improved flexibility
1 parent 20e599f commit acbae6b

10 files changed

Lines changed: 82 additions & 45 deletions

File tree

extensions/saas/sources/migration/src/main/java/tools/dynamia/modules/saas/migration/api/AccountImportOptions.java

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
*/
1111
package tools.dynamia.modules.saas.migration.api;
1212

13+
import java.io.Serializable;
14+
1315
/**
1416
* Options controlling a tenant import operation.
1517
*
@@ -22,7 +24,7 @@ public class AccountImportOptions {
2224
* When {@code null}, the import will attempt to create a new account from
2325
* the {@code account} section of the export file.
2426
*/
25-
private Long targetAccountId;
27+
private Serializable targetAccountId;
2628

2729
/** How to handle primary keys when persisting imported entities. */
2830
private IdentityStrategy identityStrategy = IdentityStrategy.REGENERATE_IDS;
@@ -38,7 +40,7 @@ public class AccountImportOptions {
3840

3941
// ─── Fluent builder ────────────────────────────────────────────────────────
4042

41-
public AccountImportOptions targetAccountId(Long targetAccountId) {
43+
public AccountImportOptions targetAccountId(Serializable targetAccountId) {
4244
this.targetAccountId = targetAccountId;
4345
return this;
4446
}
@@ -60,11 +62,11 @@ public AccountImportOptions failOnEntityError(boolean failOnEntityError) {
6062

6163
// ─── Accessors ─────────────────────────────────────────────────────────────
6264

63-
public Long getTargetAccountId() {
65+
public Serializable getTargetAccountId() {
6466
return targetAccountId;
6567
}
6668

67-
public void setTargetAccountId(Long targetAccountId) {
69+
public void setTargetAccountId(Serializable targetAccountId) {
6870
this.targetAccountId = targetAccountId;
6971
}
7072

extensions/saas/sources/migration/src/main/java/tools/dynamia/modules/saas/migration/api/AccountMigrationJobDto.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import tools.dynamia.modules.saas.migration.domain.AccountJobType;
1616
import tools.dynamia.modules.saas.migration.domain.AccountMigrationJob;
1717

18+
import java.io.Serializable;
1819
import java.time.Duration;
1920
import java.time.LocalDateTime;
2021

@@ -28,8 +29,8 @@
2829
public record AccountMigrationJobDto(
2930
Long id,
3031
String uuid,
31-
Long accountId,
32-
Long targetAccountId,
32+
Serializable accountId,
33+
Serializable targetAccountId,
3334
AccountJobType jobType,
3435
AccountJobStatus status,
3536
int progress,

extensions/saas/sources/migration/src/main/java/tools/dynamia/modules/saas/migration/api/AccountMigrationJobService.java

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
import org.springframework.web.multipart.MultipartFile;
1414
import tools.dynamia.modules.saas.migration.domain.AccountMigrationJob;
1515

16+
import java.io.Serializable;
1617
import java.util.List;
1718

1819
/**
@@ -39,7 +40,7 @@ public interface AccountMigrationJobService {
3940
* @param options export configuration
4041
* @return the newly created (PENDING) job
4142
*/
42-
AccountMigrationJobDto createExportJob(Long accountId, AccountExportOptions options);
43+
AccountMigrationJobDto createExportJob(Serializable accountId, AccountExportOptions options);
4344

4445
/**
4546
* Starts an async import job from an uploaded file.
@@ -64,7 +65,7 @@ public interface AccountMigrationJobService {
6465
* @param accountId ID of the account to back up
6566
* @return the newly created (PENDING) job
6667
*/
67-
AccountMigrationJobDto createBackupJob(Long accountId);
68+
AccountMigrationJobDto createBackupJob(Serializable accountId);
6869

6970
/**
7071
* Starts an async restore job from an uploaded file
@@ -74,7 +75,7 @@ public interface AccountMigrationJobService {
7475
* @param file multipart upload
7576
* @return the newly created (PENDING) job
7677
*/
77-
AccountMigrationJobDto createRestoreJob(Long accountId, MultipartFile file);
78+
AccountMigrationJobDto createRestoreJob(Serializable accountId, MultipartFile file);
7879

7980
/**
8081
* Returns the current state of the job identified by {@code jobUuid}.
@@ -98,7 +99,7 @@ public interface AccountMigrationJobService {
9899
* @param accountId filter by account; pass {@code null} to return all jobs
99100
* @return list of jobs ordered by creation date descending
100101
*/
101-
List<AccountMigrationJobDto> listJobs(Long accountId);
102+
List<AccountMigrationJobDto> listJobs(Serializable accountId);
102103

103104
/**
104105
* Requests cooperative cancellation of a running job.

extensions/saas/sources/migration/src/main/java/tools/dynamia/modules/saas/migration/api/AccountMigrationService.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
import java.io.InputStream;
1414
import java.io.OutputStream;
15+
import java.io.Serializable;
1516

1617
/**
1718
* High-level service for executing tenant mobility operations synchronously.
@@ -41,7 +42,7 @@ public interface AccountMigrationService {
4142
* @param listener optional progress callback; may be {@code null}
4243
* @param token optional cancellation token; may be {@code null}
4344
*/
44-
void exportTenant(Long accountId,
45+
void exportTenant(Serializable accountId,
4546
OutputStream output,
4647
AccountExportOptions options,
4748
MigrationProgressListener listener,

extensions/saas/sources/migration/src/main/java/tools/dynamia/modules/saas/migration/domain/AccountMigrationJob.java

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import tools.dynamia.modules.saas.migration.api.AccountExportOptions;
2121
import tools.dynamia.modules.saas.migration.api.AccountImportOptions;
2222

23+
import java.io.Serializable;
2324
import java.time.LocalDateTime;
2425

2526
/**
@@ -49,12 +50,13 @@ public class AccountMigrationJob extends SimpleEntity {
4950
/**
5051
* Source tenant account ID.
5152
*/
52-
private Long accountId;
53+
private String accountId;
5354

5455
/**
5556
* Target tenant account ID (used for clone/restore operations).
5657
*/
57-
private Long targetAccountId;
58+
private String targetAccountId;
59+
private String accountIdType;
5860

5961
// ─── Classification ────────────────────────────────────────────────────────
6062

@@ -166,22 +168,48 @@ public void setUuid(String uuid) {
166168
this.uuid = uuid;
167169
}
168170

169-
public Long getAccountId() {
171+
public String getAccountId() {
170172
return accountId;
171173
}
172174

173-
public void setAccountId(Long accountId) {
175+
public void setAccountId(String accountId) {
174176
this.accountId = accountId;
175177
}
176178

177-
public Long getTargetAccountId() {
179+
public void accountId(Serializable accountId) {
180+
if (accountId != null) {
181+
this.accountId = String.valueOf(accountId);
182+
this.accountIdType = accountId.getClass().getName();
183+
} else {
184+
this.accountId = null;
185+
this.accountIdType = null;
186+
}
187+
}
188+
189+
public String getTargetAccountId() {
178190
return targetAccountId;
179191
}
180192

181-
public void setTargetAccountId(Long targetAccountId) {
193+
public void setTargetAccountId(String targetAccountId) {
182194
this.targetAccountId = targetAccountId;
183195
}
184196

197+
public void targetAccountId(Serializable targetAccountId) {
198+
if (targetAccountId != null) {
199+
this.targetAccountId = String.valueOf(targetAccountId);
200+
} else {
201+
this.targetAccountId = null;
202+
}
203+
}
204+
205+
public String getAccountIdType() {
206+
return accountIdType;
207+
}
208+
209+
public void setAccountIdType(String accountIdType) {
210+
this.accountIdType = accountIdType;
211+
}
212+
185213
public AccountJobType getJobType() {
186214
return jobType;
187215
}

extensions/saas/sources/migration/src/main/java/tools/dynamia/modules/saas/migration/pipeline/ExportPipeline.java

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
import java.io.BufferedOutputStream;
3939
import java.io.IOException;
4040
import java.io.OutputStream;
41+
import java.io.Serializable;
4142
import java.lang.reflect.Field;
4243
import java.nio.file.FileVisitResult;
4344
import java.nio.file.Files;
@@ -156,7 +157,7 @@ public ExportPipeline(EntityManagerFactory emf,
156157
* @param listener optional progress callback
157158
* @param token optional cancellation token
158159
*/
159-
public void export(Long accountId,
160+
public void export(Serializable accountId,
160161
OutputStream output,
161162
AccountExportOptions options,
162163
MigrationProgressListener listener,
@@ -212,7 +213,7 @@ public void export(Long accountId,
212213
// Manifest
213214
// ─────────────────────────────────────────────────────────────────────────
214215

215-
private void writeManifestToFile(Path manifestPath, Account account, Long accountId,
216+
private void writeManifestToFile(Path manifestPath, Account account, Serializable accountId,
216217
AccountExportOptions options, List<Class<?>> ordered)
217218
throws IOException {
218219

@@ -222,7 +223,11 @@ private void writeManifestToFile(Path manifestPath, Account account, Long accoun
222223
gen.writeStartObject();
223224
gen.writeStringProperty(ExportConstants.FIELD_VERSION, ExportConstants.FORMAT_VERSION);
224225
gen.writeStringProperty(ExportConstants.FIELD_EXPORTED_AT, LocalDateTime.now().toString());
225-
gen.writeNumberProperty(ExportConstants.FIELD_SOURCE_ACCOUNT_ID, accountId);
226+
if(accountId instanceof Long accountIdNumber) {
227+
gen.writeNumberProperty(ExportConstants.FIELD_SOURCE_ACCOUNT_ID, accountIdNumber);
228+
}else{
229+
gen.writeStringProperty(ExportConstants.FIELD_SOURCE_ACCOUNT_ID, accountId.toString());
230+
}
226231
gen.writeStringProperty(ExportConstants.FIELD_IDENTITY_STRATEGY,
227232
options.getIdentityStrategy().name());
228233

@@ -250,7 +255,7 @@ private void writeManifestToFile(Path manifestPath, Account account, Long accoun
250255

251256
private void exportEntitiesInParallel(Path tempDir,
252257
List<Class<?>> ordered,
253-
Long accountId,
258+
Serializable accountId,
254259
AccountExportOptions options,
255260
CancellationToken token,
256261
int parallelism,
@@ -320,7 +325,7 @@ private void exportEntitiesInParallel(Path tempDir,
320325
* concurrently from multiple virtual threads.
321326
*/
322327
private long exportEntityToFile(Path tempDir, Class<?> entityClass,
323-
Long accountId, AccountExportOptions options,
328+
Serializable accountId, AccountExportOptions options,
324329
CancellationToken token) throws IOException {
325330

326331
Path filePath = tempDir.resolve(entityFileName(accountId, entityClass));
@@ -393,7 +398,7 @@ private void writeEmptyEntityFile(Path filePath, Class<?> entityClass) throws IO
393398
*/
394399
private long writeEntityRows(JsonGenerator gen,
395400
Class<?> entityClass,
396-
Long accountId,
401+
Serializable accountId,
397402
AccountExportOptions options,
398403
CancellationToken token,
399404
EntityManager localEm,
@@ -458,7 +463,7 @@ private long writeEntityRows(JsonGenerator gen,
458463
* Streams the temp directory contents to {@code output} as a ZIP archive.
459464
* Entries are added in topological order: manifest first, then entities.
460465
*/
461-
private void zipToOutput(Path tempDir, List<Class<?>> ordered, Long accountId,
466+
private void zipToOutput(Path tempDir, List<Class<?>> ordered, Object accountId,
462467
OutputStream output) throws IOException {
463468

464469
// Keep reference to the buffer so we can flush it after finish().
@@ -568,7 +573,7 @@ private void writeEntityRow(JsonGenerator gen, Object entity, List<ColumnDef> co
568573
// Utilities
569574
// ─────────────────────────────────────────────────────────────────────────
570575

571-
private static String entityFileName(Long accountId, Class<?> entityClass) {
576+
private static String entityFileName(Object accountId, Class<?> entityClass) {
572577
return "Account" + accountId + "_" + entityClass.getSimpleName() + ".json";
573578
}
574579

extensions/saas/sources/migration/src/main/java/tools/dynamia/modules/saas/migration/pipeline/ImportPipeline.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
import java.io.FilterInputStream;
4545
import java.io.IOException;
4646
import java.io.InputStream;
47+
import java.io.Serializable;
4748
import java.lang.reflect.Field;
4849
import java.util.ArrayList;
4950
import java.util.HashMap;
@@ -64,8 +65,7 @@
6465
* {@code entityClass} → {@code fields} → {@code rows} in streaming mode.</li>
6566
* <li>Rows are accumulated into chunks and persisted via
6667
* {@link #persistChunk} in isolated transactions.</li>
67-
* <li>{@link #closeEntry} is called after each entry so the stream
68-
* advances cleanly to the next one.</li>
68+
*
6969
* </ol>
7070
*
7171
* <p>Entities arrive in the same topological order they were written by
@@ -382,7 +382,7 @@ public int persistChunk(List<JsonNode> chunk,
382382
private Object deserializeEntity(JsonNode node,
383383
Class<?> entityClass,
384384
EntityType<?> entityType,
385-
Long targetAccountId,
385+
Serializable targetAccountId,
386386
IdentityMapper identityMapper,
387387
Map<String, Map<Object, Object>> idMappings) throws Exception {
388388

extensions/saas/sources/migration/src/main/java/tools/dynamia/modules/saas/migration/services/AccountMigrationJobServiceImpl.java

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
import tools.dynamia.commons.logger.LoggingService;
1414
import tools.dynamia.domain.query.QueryConditions;
15+
import tools.dynamia.modules.saas.migration.api.MigrationProgressListener;
1516
import tools.jackson.databind.ObjectMapper;
1617
import org.springframework.beans.factory.annotation.Qualifier;
1718
import org.springframework.web.multipart.MultipartFile;
@@ -39,6 +40,7 @@
3940

4041
import java.io.IOException;
4142
import java.io.InputStream;
43+
import java.io.Serializable;
4244
import java.nio.file.Files;
4345
import java.nio.file.Path;
4446
import java.nio.file.Paths;
@@ -98,14 +100,14 @@ public AccountMigrationJobServiceImpl(CrudService crudService,
98100
// ─────────────────────────────────────────────────────────────────────────
99101

100102
@Override
101-
public AccountMigrationJobDto createExportJob(Long accountId, AccountExportOptions options) {
103+
public AccountMigrationJobDto createExportJob(Serializable accountId, AccountExportOptions options) {
102104
AccountMigrationJob job = createAndSaveJob(accountId, null, AccountJobType.EXPORT, options);
103105
launchExportJob(job, accountId, options);
104106
return toDto(job);
105107
}
106108

107109
@Override
108-
public AccountMigrationJobDto createBackupJob(Long accountId) {
110+
public AccountMigrationJobDto createBackupJob(Serializable accountId) {
109111
AccountExportOptions options = new AccountExportOptions()
110112
.label("backup");
111113
AccountMigrationJob job = createAndSaveJob(accountId, null, AccountJobType.BACKUP, options);
@@ -122,7 +124,7 @@ public AccountMigrationJobDto createImportJob(MultipartFile file, AccountImportO
122124
}
123125

124126
@Override
125-
public AccountMigrationJobDto createRestoreJob(Long accountId, MultipartFile file) {
127+
public AccountMigrationJobDto createRestoreJob(Serializable accountId, MultipartFile file) {
126128
Path savedFile = saveUploadedFile(file, "restore");
127129
AccountImportOptions options = new AccountImportOptions()
128130
.targetAccountId(accountId)
@@ -156,7 +158,7 @@ public AccountMigrationJob getJobEntity(String jobUuid) {
156158
}
157159

158160
@Override
159-
public List<AccountMigrationJobDto> listJobs(Long accountId) {
161+
public List<AccountMigrationJobDto> listJobs(Serializable accountId) {
160162
QueryParameters qp = new QueryParameters()
161163
.orderBy("createdAt", false);
162164
if (accountId != null) {
@@ -194,7 +196,7 @@ public void cancelJob(String jobUuid) {
194196
// Worker launchers
195197
// ─────────────────────────────────────────────────────────────────────────
196198

197-
private void launchExportJob(AccountMigrationJob job, Long accountId, AccountExportOptions options) {
199+
private void launchExportJob(AccountMigrationJob job, Serializable accountId, AccountExportOptions options) {
198200
CancellationToken token = CancellationToken.active();
199201
activeTokens.put(job.getUuid(), token);
200202
Path outputFile = buildOutputPath(job);
@@ -267,11 +269,11 @@ public Boolean doWorkWithResult() {
267269
// Helpers
268270
// ─────────────────────────────────────────────────────────────────────────
269271

270-
private AccountMigrationJob createAndSaveJob(Long accountId, Long targetAccountId,
272+
private AccountMigrationJob createAndSaveJob(Serializable accountId, Serializable targetAccountId,
271273
AccountJobType type, Object options) {
272274
AccountMigrationJob job = new AccountMigrationJob();
273-
job.setAccountId(accountId);
274-
job.setTargetAccountId(targetAccountId);
275+
job.accountId(accountId);
276+
job.targetAccountId(targetAccountId);
275277
job.setJobType(type);
276278
job.setStatus(AccountJobStatus.PENDING);
277279
if (options != null) {
@@ -318,7 +320,7 @@ private void finalizeJob(String jobUuid, Throwable ex, Path resultFile, Cancella
318320
});
319321
}
320322

321-
private tools.dynamia.modules.saas.migration.api.MigrationProgressListener buildProgressListener(
323+
private MigrationProgressListener buildProgressListener(
322324
AccountMigrationJob job) {
323325
// Mark the job as RUNNING on first progress event, then persist progress updates
324326
final boolean[] started = {false};

0 commit comments

Comments
 (0)