When your cloud app declares a migration:managedExports module (see Onboarding to SAM), Atlassian exports that data for you during the migration. As a result, your Data Center (DC) app no longer needs to migrate it.
Your DC app can check at runtime which managed exports are enabled for the current migration. Use this to skip any part of your own migration code that Atlassian now covers, so the same data isn't migrated twice. For example, you can stop sending your own custom field values or attachments when Atlassian exports them.
The configuration comes from the cloud app installed on the destination site for that migration. It reflects the migration:managedExports module of the cloud app version and environment being migrated to as well as what is available within the migrating DC server.
atlassian-app-cloud-migration-listener version 1.8.9 or later.isEnabled() == false.1 2 3 4 5 6<dependency> <groupId>com.atlassian</groupId> <artifactId>atlassian-app-cloud-migration-listener</artifactId> <version>1.8.9</version> </dependency>
Call getManagedExports() on the migration gateway that your listener receives. The method is available on both gateway types:
| Listener type | Gateway | Method |
|---|---|---|
DiscoverableForgeListener (Forge) | AppCloudForgeMigrationGateway | ManagedExports getManagedExports() |
DiscoverableListener (Connect) | AppCloudMigrationGateway | ManagedExports getManagedExports() |
The result is scoped to the current migration (transfer). Call it during the migration, for example from onStartAppMigration, rather than caching it across migrations.
Older JCMA and CCMA versions don't implement getManagedExports() and throw an UnsupportedOperationException. Always wrap the call in a try/catch. If it throws, treat every managed export as disabled and fall back to your existing migration code.
ManagedExports interfacecom.atlassian.migration.app.gateway.ManagedExports gives you one exporter per managed export type. Each exporter has an isEnabled() method, plus a method that tells you exactly what Atlassian will export.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28public interface ManagedExports { MappingExporter getMappingExporter(); BinaryExporter getBinaryExporter(); DatabaseExporter getDatabaseExporter(); CustomFieldValuesExporter getCustomFieldValuesExporter(); interface MappingExporter { boolean isEnabled(); List<String> getEntityTypes(); } interface BinaryExporter { boolean isEnabled(); List<String> getDirectories(); } interface DatabaseExporter { boolean isEnabled(); List<String> getTables(); } interface CustomFieldValuesExporter { boolean isEnabled(); List<String> getCustomFieldTypes(); List<String> getCustomFieldNames(); } }
An exporter counts as enabled only when SAM is enabled for the migration and your cloud app's manifest declares a non-empty configuration for that export type. If an exporter is disabled, its detail methods return an empty list.
| Exporter | Manifest entry | isEnabled() returns true when… | Detail method | Returned value |
|---|---|---|---|---|
MappingExporter | mapping → entityTypes | Atlassian will export at least one entity type. | getEntityTypes() | The entity types whose mappings will be exported, for example jira:issue. Returns ["*"] if all entity types are exported. |
BinaryExporter | binary → directoryPrefix | Atlassian will export at least one directory. | getDirectories() | The directory prefixes, relative to the product home directory, whose files will be exported as binary data. Returns ["/"] if the whole home directory is exported. |
DatabaseExporter | AO tables (Early Access) | Atlassian will export at least one table. | getTables() | The AO tables that will be exported (see the AO File Specification). Returns ["*"] if all your app's tables are exported. |
CustomFieldValuesExporter | customFieldValues → fields | At least one fields entry declares a server.typeKey. | getCustomFieldTypes() | The distinct DC custom field type keys (server.typeKey) whose values JCMA will export. See Custom Field Values. |
The values "*" (mappings and database) and "/" (binary) mean "export everything". Check for them before you compare individual entries.
The following example uses a Forge listener. For a Connect listener, call getManagedExports() on the AppCloudMigrationGateway passed to onStartAppMigration in the same way.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53@Override public void onStartAppMigration(AppCloudForgeMigrationGateway gateway, MigrationDetailsV1 migrationDetails) { ManagedExports managedExports = null; try { managedExports = gateway.getManagedExports(); } catch (UnsupportedOperationException e) { // JCMA/CCMA is too old to support managed exports. Fall back to migrating everything yourself. log.info("Managed exports are not supported by this version of JCMA/CCMA", e); } // Mappings boolean mappingsManaged = managedExports != null && managedExports.getMappingExporter().isEnabled(); List<String> managedEntityTypes = mappingsManaged ? managedExports.getMappingExporter().getEntityTypes() : Collections.emptyList(); // Binary data (attachments and other files) boolean binaryManaged = managedExports != null && managedExports.getBinaryExporter().isEnabled(); List<String> managedDirectories = binaryManaged ? managedExports.getBinaryExporter().getDirectories() : Collections.emptyList(); // AO tables boolean databaseManaged = managedExports != null && managedExports.getDatabaseExporter().isEnabled(); List<String> managedTables = databaseManaged ? managedExports.getDatabaseExporter().getTables() : Collections.emptyList(); // Custom field values boolean customFieldValuesManaged = managedExports != null && managedExports.getCustomFieldValuesExporter().isEnabled(); List<String> managedCustomFieldTypes = customFieldValuesManaged ? managedExports.getCustomFieldValuesExporter().getCustomFieldTypes() : Collections.emptyList(); // Entity properties (not yet supported, always disabled) boolean entityPropertiesManaged = managedExports != null && managedExports.getEntityPropertyExporter().isEnabled(); if (!managedCustomFieldTypes.contains("com.vendor.my-app:my-custom-field-type")) { migrateCustomFieldValues(gateway); } if (!binaryManaged) { uploadAttachments(gateway); } else if (!managedDirectories.contains("/")) { // Upload only the files outside the directories Atlassian exports as defined by your cloud app. uploadAttachmentsExcluding(gateway, managedDirectories); } // ...apply the same approach to mappings, AO tables and entity properties. }
Every exporter is disabled, but my manifest declares migration:managedExports.
migration:managedExports module is deployed to the Forge environment and installed on the destination site you're migrating to.DiscoverableForgeListener uses its Forge app ID and environment; a DiscoverableListener uses its cloud app key.getManagedExports() throws UnsupportedOperationException.
The JCMA or CCMA version running the migration doesn't support managed exports. Upgrade the migration assistant or handle the exception as shown in the example.
Rate this page: