Java tutorial
/* * Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.wso2.carbon.apimgt.migration.client; import org.apache.commons.io.IOUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.wso2.carbon.apimgt.api.model.APIStatus; import org.wso2.carbon.apimgt.impl.APIConstants; import org.wso2.carbon.apimgt.impl.utils.APIMgtDBUtil; import org.wso2.carbon.apimgt.migration.APIMigrationException; import org.wso2.carbon.apimgt.migration.client._110Specific.ResourceModifier; import org.wso2.carbon.apimgt.migration.client._110Specific.dto.*; import org.wso2.carbon.apimgt.migration.util.Constants; import org.wso2.carbon.apimgt.migration.util.RegistryService; import org.wso2.carbon.apimgt.migration.util.ResourceUtil; import org.wso2.carbon.apimgt.migration.util.StatDBUtil; import org.wso2.carbon.governance.api.exception.GovernanceException; import org.wso2.carbon.governance.api.generic.dataobjects.GenericArtifact; import org.wso2.carbon.registry.api.RegistryException; import org.wso2.carbon.registry.core.RegistryConstants; import org.wso2.carbon.user.api.Tenant; import org.wso2.carbon.user.api.UserStoreException; import org.wso2.carbon.user.core.tenant.TenantManager; import org.wso2.carbon.utils.CarbonUtils; import org.wso2.carbon.utils.FileUtil; import org.wso2.carbon.utils.multitenancy.MultitenantUtils; import javax.xml.stream.XMLStreamException; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.sql.*; import java.util.List; import java.util.ArrayList; import java.util.HashMap; public class MigrateFrom19to110 extends MigrationClientBase implements MigrationClient { private static final Log log = LogFactory.getLog(MigrateFrom19to110.class); private RegistryService registryService; private boolean removeDecryptionFailedKeysFromDB; private static class AccessTokenInfo { AccessTokenInfo(String usernameWithoutDomain, String authzUser) { this.usernameWithoutDomain = usernameWithoutDomain; this.authzUser = authzUser; } String usernameWithoutDomain; String authzUser; } public MigrateFrom19to110(String tenantArguments, String blackListTenantArguments, RegistryService registryService, TenantManager tenantManager, boolean removeDecryptionFailedKeysFromDB) throws UserStoreException { super(tenantArguments, blackListTenantArguments, tenantManager); this.registryService = registryService; this.removeDecryptionFailedKeysFromDB = removeDecryptionFailedKeysFromDB; } @Override public void databaseMigration() throws APIMigrationException, SQLException { String amScriptPath = CarbonUtils.getCarbonHome() + File.separator + "migration-scripts" + File.separator + "19-110-migration" + File.separator; updateAPIManagerDatabase(amScriptPath); //updateAuthzUserName(); if (StatDBUtil.isTokenEncryptionEnabled()) { decryptEncryptedConsumerKeys(); } } @Override public void registryResourceMigration() throws APIMigrationException { rxtMigration(); workflowExtensionsMigration(); updateTiers(); migrateLifeCycles(); } @Override public void fileSystemMigration() throws APIMigrationException { synapseAPIMigration(); } @Override public void cleanOldResources() throws APIMigrationException { } @Override public void statsMigration() throws APIMigrationException { } @Override public void optionalMigration(List<String> options) throws APIMigrationException { //no implementation is required } private void synapseAPIMigration() { for (Tenant tenant : getTenantsArray()) { try { String apiPath = ResourceUtil.getApiPath(tenant.getId(), tenant.getDomain()); List<SynapseDTO> synapseDTOs = ResourceUtil.getVersionedAPIs(apiPath); ResourceModifier.updateSynapseConfigs(synapseDTOs); for (SynapseDTO synapseDTO : synapseDTOs) { ResourceUtil.transformXMLDocument(synapseDTO.getDocument(), synapseDTO.getFile()); } } catch (Exception e) { log.error("Unable to do the Synapse API migration of tenant : " + tenant.getDomain()); } } } private void updateAuthzUserName() throws SQLException { log.info("Updating Authz UserName for API Manager started"); Connection connection = null; PreparedStatement selectStatement = null; ResultSet resultSet = null; ArrayList<AccessTokenInfo> updateValues = new ArrayList<>(); try { String selectQuery = "SELECT DISTINCT AUTHZ_USER FROM IDN_OAUTH2_ACCESS_TOKEN WHERE AUTHZ_USER LIKE '%@%'"; connection = APIMgtDBUtil.getConnection(); selectStatement = connection.prepareStatement(selectQuery); resultSet = selectStatement.executeQuery(); while (resultSet.next()) { String authzUser = resultSet.getString("AUTHZ_USER"); String usernameWithoutDomain = MultitenantUtils.getTenantAwareUsername(authzUser); AccessTokenInfo accessTokenInfo = new AccessTokenInfo(usernameWithoutDomain, authzUser); updateValues.add(accessTokenInfo); } } finally { APIMgtDBUtil.closeAllConnections(selectStatement, connection, resultSet); } if (!updateValues.isEmpty()) { // If user names that need to be updated exist PreparedStatement updateStatement = null; try { connection = APIMgtDBUtil.getConnection(); connection.setAutoCommit(false); updateStatement = connection.prepareStatement( "UPDATE IDN_OAUTH2_ACCESS_TOKEN SET AUTHZ_USER = ?" + " WHERE AUTHZ_USER = ?"); for (AccessTokenInfo accessTokenInfo : updateValues) { updateStatement.setString(1, accessTokenInfo.usernameWithoutDomain); updateStatement.setString(2, accessTokenInfo.authzUser); updateStatement.addBatch(); } updateStatement.executeBatch(); connection.commit(); } finally { APIMgtDBUtil.closeAllConnections(updateStatement, connection, null); } } log.info("Updating Authz UserName for API Manager completed"); } private void decryptEncryptedConsumerKeys() throws SQLException { log.info("Decrypting encrypted consumer keys started"); Connection connection = null; try { connection = APIMgtDBUtil.getConnection(); connection.setAutoCommit(false); if (updateAMApplicationKeyMapping(connection)) { if (updateAMAppKeyDomainMapping(connection)) { if (updateIdnTableConsumerKeys(connection)) { connection.commit(); } } } } finally { APIMgtDBUtil.closeAllConnections(null, connection, null); } log.info("Decrypting encrypted consumer keys completed"); } private boolean updateAMApplicationKeyMapping(Connection connection) throws SQLException { log.info("Updating consumer keys in AM_APPLICATION_KEY_MAPPING"); PreparedStatement preparedStatementUpdate = null; PreparedStatement preparedStatementDelete = null; Statement statement = null; ResultSet resultSet = null; boolean continueUpdatingDB = true; long totalRecords = 0; long decryptionFailedRecords = 0; try { String query = "SELECT APPLICATION_ID, CONSUMER_KEY, KEY_TYPE FROM AM_APPLICATION_KEY_MAPPING"; ArrayList<AppKeyMappingTableDTO> appKeyMappingTableDTOs = new ArrayList<>(); ArrayList<AppKeyMappingTableDTO> appKeyMappingTableDTOsFailed = new ArrayList<>(); statement = connection.createStatement(); statement.setFetchSize(50); resultSet = statement.executeQuery(query); while (resultSet.next()) { ConsumerKeyDTO consumerKeyDTO = new ConsumerKeyDTO(); consumerKeyDTO.setEncryptedConsumerKey(resultSet.getString("CONSUMER_KEY")); AppKeyMappingTableDTO appKeyMappingTableDTO = new AppKeyMappingTableDTO(); appKeyMappingTableDTO.setApplicationId(resultSet.getString("APPLICATION_ID")); appKeyMappingTableDTO.setConsumerKey(consumerKeyDTO); appKeyMappingTableDTO.setKeyType(resultSet.getString("KEY_TYPE")); totalRecords++; if (ResourceModifier.decryptConsumerKeyIfEncrypted(consumerKeyDTO)) { appKeyMappingTableDTOs.add(appKeyMappingTableDTO); log.debug("Successfully decrypted consumer key : " + consumerKeyDTO.getEncryptedConsumerKey() + " as : " + consumerKeyDTO.getDecryptedConsumerKey() + " in AM_APPLICATION_KEY_MAPPING table"); } else { log.error("Cannot decrypt consumer key : " + consumerKeyDTO.getEncryptedConsumerKey() + " in AM_APPLICATION_KEY_MAPPING table"); decryptionFailedRecords++; appKeyMappingTableDTOsFailed.add(appKeyMappingTableDTO); //If its not allowed to remove decryption failed entries from DB, we will not continue updating // tables even with successfully decrypted entries to maintain DB integrity if (!removeDecryptionFailedKeysFromDB) { continueUpdatingDB = false; } } } if (continueUpdatingDB) { preparedStatementUpdate = connection .prepareStatement("UPDATE AM_APPLICATION_KEY_MAPPING SET CONSUMER_KEY = ?" + " WHERE APPLICATION_ID = ? AND KEY_TYPE = ?"); for (AppKeyMappingTableDTO appKeyMappingTableDTO : appKeyMappingTableDTOs) { preparedStatementUpdate.setString(1, appKeyMappingTableDTO.getConsumerKey().getDecryptedConsumerKey()); preparedStatementUpdate.setString(2, appKeyMappingTableDTO.getApplicationId()); preparedStatementUpdate.setString(3, appKeyMappingTableDTO.getKeyType()); preparedStatementUpdate.addBatch(); } preparedStatementUpdate.executeBatch(); //deleting rows where consumer key decryption was unsuccessful preparedStatementDelete = connection .prepareStatement("DELETE FROM AM_APPLICATION_KEY_MAPPING WHERE CONSUMER_KEY = ?"); for (AppKeyMappingTableDTO appKeyMappingTableDTO : appKeyMappingTableDTOsFailed) { preparedStatementDelete.setString(1, appKeyMappingTableDTO.getConsumerKey().getEncryptedConsumerKey()); preparedStatementDelete.addBatch(); } preparedStatementDelete.executeBatch(); log.info("AM_APPLICATION_KEY_MAPPING table updated with " + decryptionFailedRecords + "/" + totalRecords + " of the CONSUMER_KEY entries deleted as they cannot be decrypted"); } else { log.error("AM_APPLICATION_KEY_MAPPING table not updated as " + decryptionFailedRecords + "/" + totalRecords + " of the CONSUMER_KEY entries cannot be decrypted"); } } finally { APIMgtDBUtil.closeAllConnections(null, null, resultSet); APIMgtDBUtil.closeAllConnections(preparedStatementUpdate, null, null); APIMgtDBUtil.closeAllConnections(preparedStatementDelete, null, null); if (statement != null) { try { statement.close(); } catch (SQLException e) { log.error("Unable to close the statement", e); } } } return continueUpdatingDB; } private boolean updateAMAppKeyDomainMapping(Connection connection) throws SQLException { log.info("Updating consumer keys in AM_APP_KEY_DOMAIN_MAPPING"); Statement selectStatement = null; Statement deleteStatement = null; PreparedStatement preparedStatement = null; ResultSet resultSet = null; boolean continueUpdatingDB = true; long totalRecords = 0; long decryptionFailedRecords = 0; try { ArrayList<KeyDomainMappingTableDTO> keyDomainMappingTableDTOs = new ArrayList<>(); String query = "SELECT * FROM AM_APP_KEY_DOMAIN_MAPPING"; selectStatement = connection.createStatement(); selectStatement.setFetchSize(50); resultSet = selectStatement.executeQuery(query); while (resultSet.next()) { ConsumerKeyDTO consumerKeyDTO = new ConsumerKeyDTO(); consumerKeyDTO.setEncryptedConsumerKey(resultSet.getString("CONSUMER_KEY")); totalRecords++; if (ResourceModifier.decryptConsumerKeyIfEncrypted(consumerKeyDTO)) { KeyDomainMappingTableDTO keyDomainMappingTableDTO = new KeyDomainMappingTableDTO(); keyDomainMappingTableDTO.setConsumerKey(consumerKeyDTO); keyDomainMappingTableDTO.setAuthzDomain(resultSet.getString("AUTHZ_DOMAIN")); keyDomainMappingTableDTOs.add(keyDomainMappingTableDTO); } else { log.error("Cannot decrypt consumer key : " + consumerKeyDTO.getEncryptedConsumerKey() + " in AM_APP_KEY_DOMAIN_MAPPING table"); decryptionFailedRecords++; //If its not allowed to remove decryption failed entries from DB, we will not continue updating // tables even with successfully decrypted entries to maintain DB integrity if (!removeDecryptionFailedKeysFromDB) { continueUpdatingDB = false; } } } if (continueUpdatingDB) { // Modify table only if decryption is successful preparedStatement = connection.prepareStatement( "INSERT INTO AM_APP_KEY_DOMAIN_MAPPING " + "(CONSUMER_KEY, AUTHZ_DOMAIN) VALUES (?, ?)"); for (KeyDomainMappingTableDTO keyDomainMappingTableDTO : keyDomainMappingTableDTOs) { preparedStatement.setString(1, keyDomainMappingTableDTO.getConsumerKey().getDecryptedConsumerKey()); preparedStatement.setString(2, keyDomainMappingTableDTO.getAuthzDomain()); preparedStatement.addBatch(); } deleteStatement = connection.createStatement(); deleteStatement.execute("DELETE FROM AM_APP_KEY_DOMAIN_MAPPING"); preparedStatement.executeBatch(); log.info("AM_APP_KEY_DOMAIN_MAPPING table updated with " + decryptionFailedRecords + "/" + totalRecords + " of the CONSUMER_KEY entries deleted as they cannot be decrypted"); } else { log.error("AM_APP_KEY_DOMAIN_MAPPING table not updated as " + decryptionFailedRecords + "/" + totalRecords + " of the CONSUMER_KEY entries" + " cannot be decrypted"); } } finally { if (selectStatement != null) selectStatement.close(); if (deleteStatement != null) deleteStatement.close(); if (preparedStatement != null) preparedStatement.close(); if (resultSet != null) resultSet.close(); } return continueUpdatingDB; } private boolean updateIdnTableConsumerKeys(Connection connection) throws SQLException { log.info("Updating consumer keys in IDN Tables"); Statement consumerAppsLookup = null; PreparedStatement consumerAppsDelete = null; PreparedStatement consumerAppsInsert = null; PreparedStatement consumerAppsDeleteFailedRecords = null; PreparedStatement accessTokenUpdate = null; PreparedStatement accessTokenDelete = null; ResultSet consumerAppsResultSet = null; boolean continueUpdatingDB = true; try { String consumerAppsQuery = "SELECT * FROM IDN_OAUTH_CONSUMER_APPS"; consumerAppsLookup = connection.createStatement(); consumerAppsLookup.setFetchSize(50); consumerAppsResultSet = consumerAppsLookup.executeQuery(consumerAppsQuery); ArrayList<ConsumerAppsTableDTO> consumerAppsTableDTOs = new ArrayList<>(); ArrayList<ConsumerAppsTableDTO> consumerAppsTableDTOsFailed = new ArrayList<>(); while (consumerAppsResultSet.next()) { ConsumerKeyDTO consumerKeyDTO = new ConsumerKeyDTO(); consumerKeyDTO.setEncryptedConsumerKey(consumerAppsResultSet.getString("CONSUMER_KEY")); ConsumerAppsTableDTO consumerAppsTableDTO = new ConsumerAppsTableDTO(); consumerAppsTableDTO.setConsumerKey(consumerKeyDTO); consumerAppsTableDTO.setConsumerSecret(consumerAppsResultSet.getString("CONSUMER_SECRET")); consumerAppsTableDTO.setUsername(consumerAppsResultSet.getString("USERNAME")); consumerAppsTableDTO.setTenantID(consumerAppsResultSet.getInt("TENANT_ID")); consumerAppsTableDTO.setAppName(consumerAppsResultSet.getString("APP_NAME")); consumerAppsTableDTO.setOauthVersion(consumerAppsResultSet.getString("OAUTH_VERSION")); consumerAppsTableDTO.setCallbackURL(consumerAppsResultSet.getString("CALLBACK_URL")); consumerAppsTableDTO.setGrantTypes(consumerAppsResultSet.getString("GRANT_TYPES")); if (ResourceModifier.decryptConsumerKeyIfEncrypted(consumerKeyDTO)) { consumerAppsTableDTOs.add(consumerAppsTableDTO); if (log.isDebugEnabled()) { log.debug("Successfully decrypted consumer key : " + consumerKeyDTO.getEncryptedConsumerKey() + " in IDN_OAUTH_CONSUMER_APPS table"); } } else { consumerAppsTableDTOsFailed.add(consumerAppsTableDTO); log.error("Cannot decrypt consumer key : " + consumerKeyDTO.getEncryptedConsumerKey() + " in IDN_OAUTH_CONSUMER_APPS table"); //If its not allowed to remove decryption failed entries from DB, we will not continue updating // tables even with successfully decrypted entries to maintain DB integrity if (!removeDecryptionFailedKeysFromDB) { continueUpdatingDB = false; } } } if (continueUpdatingDB) { // Add new entries for decrypted consumer keys into IDN_OAUTH_CONSUMER_APPS consumerAppsInsert = connection .prepareStatement("INSERT INTO IDN_OAUTH_CONSUMER_APPS (CONSUMER_KEY, " + "CONSUMER_SECRET, USERNAME, TENANT_ID, APP_NAME, OAUTH_VERSION, " + "CALLBACK_URL, GRANT_TYPES) VALUES (?, ?, ?, ?, ?, ?, ?, ?)"); for (ConsumerAppsTableDTO consumerAppsTableDTO : consumerAppsTableDTOs) { updateIdnConsumerApps(consumerAppsInsert, consumerAppsTableDTO); } consumerAppsInsert.executeBatch(); log.info("Inserted entries in IDN_OAUTH_CONSUMER_APPS"); // Update IDN_OAUTH2_ACCESS_TOKEN foreign key reference to CONSUMER_KEY accessTokenUpdate = connection.prepareStatement( "UPDATE IDN_OAUTH2_ACCESS_TOKEN SET CONSUMER_KEY = ? " + "WHERE CONSUMER_KEY = ?"); for (ConsumerAppsTableDTO consumerAppsTableDTO : consumerAppsTableDTOs) { ConsumerKeyDTO consumerKeyDTO = consumerAppsTableDTO.getConsumerKey(); updateIdnAccessToken(accessTokenUpdate, consumerKeyDTO); } accessTokenUpdate.executeBatch(); log.info("Updated entries in IDN_OAUTH2_ACCESS_TOKEN"); // Remove redundant records in IDN_OAUTH_CONSUMER_APPS consumerAppsDelete = connection .prepareStatement("DELETE FROM IDN_OAUTH_CONSUMER_APPS WHERE " + "CONSUMER_KEY = ?"); for (ConsumerAppsTableDTO consumerAppsTableDTO : consumerAppsTableDTOs) { ConsumerKeyDTO consumerKeyDTO = consumerAppsTableDTO.getConsumerKey(); deleteIdnConsumerApps(consumerAppsDelete, consumerKeyDTO); } consumerAppsDelete.executeBatch(); log.info("Removed redundant entries in IDN_OAUTH_CONSUMER_APPS"); //deleting rows where consumer key decryption was unsuccessful from IDN_OAUTH_CONSUMER_APPS table consumerAppsDeleteFailedRecords = connection .prepareStatement("DELETE FROM IDN_OAUTH_CONSUMER_APPS WHERE " + "CONSUMER_KEY = ?"); for (ConsumerAppsTableDTO consumerAppsTableDTO : consumerAppsTableDTOsFailed) { ConsumerKeyDTO consumerKeyDTO = consumerAppsTableDTO.getConsumerKey(); deleteIdnConsumerApps(consumerAppsDeleteFailedRecords, consumerKeyDTO); } consumerAppsDeleteFailedRecords.executeBatch(); log.info("Removed decryption failed entries in IDN_OAUTH_CONSUMER_APPS"); //deleting rows where consumer key decryption was unsuccessful from IDN_OAUTH2_ACCESS_TOKEN table accessTokenDelete = connection .prepareStatement("DELETE FROM IDN_OAUTH2_ACCESS_TOKEN " + "WHERE CONSUMER_KEY = ?"); for (ConsumerAppsTableDTO consumerAppsTableDTO : consumerAppsTableDTOsFailed) { ConsumerKeyDTO consumerKeyDTO = consumerAppsTableDTO.getConsumerKey(); deleteIdnAccessToken(consumerAppsDeleteFailedRecords, consumerKeyDTO); } accessTokenDelete.executeBatch(); log.info("Removed decryption failed entries in IDN_OAUTH2_ACCESS_TOKEN"); } } finally { if (consumerAppsLookup != null) consumerAppsLookup.close(); if (consumerAppsDelete != null) consumerAppsDelete.close(); if (consumerAppsDeleteFailedRecords != null) consumerAppsDeleteFailedRecords.close(); if (consumerAppsInsert != null) consumerAppsInsert.close(); if (accessTokenUpdate != null) accessTokenUpdate.close(); if (accessTokenDelete != null) accessTokenDelete.close(); if (consumerAppsResultSet != null) consumerAppsResultSet.close(); } return continueUpdatingDB; } private void updateIdnConsumerApps(PreparedStatement consumerAppsInsert, ConsumerAppsTableDTO consumerAppsTableDTO) throws SQLException { consumerAppsInsert.setString(1, consumerAppsTableDTO.getConsumerKey().getDecryptedConsumerKey()); consumerAppsInsert.setString(2, consumerAppsTableDTO.getConsumerSecret()); consumerAppsInsert.setString(3, consumerAppsTableDTO.getUsername()); consumerAppsInsert.setInt(4, consumerAppsTableDTO.getTenantID()); consumerAppsInsert.setString(5, consumerAppsTableDTO.getAppName()); consumerAppsInsert.setString(6, consumerAppsTableDTO.getOauthVersion()); consumerAppsInsert.setString(7, consumerAppsTableDTO.getCallbackURL()); consumerAppsInsert.setString(8, consumerAppsTableDTO.getGrantTypes()); consumerAppsInsert.addBatch(); } private void updateIdnAccessToken(PreparedStatement accessTokenUpdate, ConsumerKeyDTO consumerKeyDTO) throws SQLException { accessTokenUpdate.setString(1, consumerKeyDTO.getDecryptedConsumerKey()); accessTokenUpdate.setString(2, consumerKeyDTO.getEncryptedConsumerKey()); accessTokenUpdate.addBatch(); } private void deleteIdnAccessToken(PreparedStatement accessTokenDelete, ConsumerKeyDTO consumerKeyDTO) throws SQLException { accessTokenDelete.setString(1, consumerKeyDTO.getEncryptedConsumerKey()); accessTokenDelete.addBatch(); } private void deleteIdnConsumerApps(PreparedStatement consumerAppsDelete, ConsumerKeyDTO consumerKeyDTO) throws SQLException { consumerAppsDelete.setString(1, consumerKeyDTO.getEncryptedConsumerKey()); consumerAppsDelete.addBatch(); } /** * This method is used to migrate rxt and rxt data * This adds three new attributes to the api rxt * * @throws APIMigrationException */ private void rxtMigration() throws APIMigrationException { log.info("Rxt migration for API Manager started."); String rxtName = "api.rxt"; String rxtDir = CarbonUtils.getCarbonHome() + File.separator + "migration-scripts" + File.separator + "19-110-migration" + File.separator + "rxts" + File.separator + rxtName; for (Tenant tenant : getTenantsArray()) { try { registryService.startTenantFlow(tenant); log.info("Updating api.rxt for tenant " + tenant.getId() + '(' + tenant.getDomain() + ')'); //Update api.rxt file String rxt = FileUtil.readFileToString(rxtDir); registryService.updateRXTResource(rxtName, rxt); log.info("End Updating api.rxt for tenant " + tenant.getId() + '(' + tenant.getDomain() + ')'); log.info("Start rxt data migration for tenant " + tenant.getId() + '(' + tenant.getDomain() + ')'); GenericArtifact[] artifacts = registryService.getGenericAPIArtifacts(); for (GenericArtifact artifact : artifacts) { artifact.setAttribute("overview_endpointAuthDigest", "false"); } registryService.updateGenericAPIArtifacts(artifacts); log.info("End rxt data migration for tenant " + tenant.getId() + '(' + tenant.getDomain() + ')'); } catch (GovernanceException e) { log.error("Error when accessing API artifact in registry for tenant " + tenant.getId() + '(' + tenant.getDomain() + ')', e); } catch (IOException e) { log.error("Error when reading api.rxt from " + rxtDir + "for tenant " + tenant.getId() + '(' + tenant.getDomain() + ')', e); } catch (org.wso2.carbon.registry.core.exceptions.RegistryException e) { log.error("Error while updating api.rxt in the registry for tenant " + tenant.getId() + '(' + tenant.getDomain() + ')', e); } catch (UserStoreException e) { log.error("Error while updating api.rxt in the registry for tenant " + tenant.getId() + '(' + tenant.getDomain() + ')', e); } finally { registryService.endTenantFlow(); } } log.info("Rxt resource migration done for all the tenants"); } /** * This method is used to workflow-extensions.xml configuration by handling the addition of the executors * to handle work flow executors * * @throws APIMigrationException */ private void workflowExtensionsMigration() throws APIMigrationException { log.info("Workflow Extensions configuration file migration for API Manager started."); for (Tenant tenant : getTenantsArray()) { log.info("Start workflow extensions configuration migration for tenant " + tenant.getId() + '(' + tenant.getDomain() + ')'); try { registryService.startTenantFlow(tenant); if (!registryService.isGovernanceRegistryResourceExists(APIConstants.WORKFLOW_EXECUTOR_LOCATION)) { if (log.isDebugEnabled()) { log.debug("Workflow extensions resource does not exist for tenant " + tenant.getId() + '(' + tenant.getDomain() + ')'); } continue; } String workFlowExtensions = ResourceUtil.getResourceContent( registryService.getGovernanceRegistryResource(APIConstants.WORKFLOW_EXECUTOR_LOCATION)); String updatedWorkFlowExtensions = ResourceModifier.modifyWorkFlowExtensions(workFlowExtensions); registryService.updateGovernanceRegistryResource(APIConstants.WORKFLOW_EXECUTOR_LOCATION, updatedWorkFlowExtensions); } catch (RegistryException e) { log.error("Error occurred while accessing the registry for tenant " + tenant.getId() + '(' + tenant.getDomain() + ')', e); } catch (UserStoreException e) { log.error("Error occurred while accessing the user store " + tenant.getId() + '(' + tenant.getDomain() + ')', e); } finally { registryService.endTenantFlow(); } log.info("End workflow extensions configuration migration for tenant " + tenant.getId() + '(' + tenant.getDomain() + ')'); } log.info("Workflow Extensions configuration file migration done for all the tenants"); } private void updateTiers() throws APIMigrationException { log.info("Tiers configuration migration for API Manager started."); for (Tenant tenant : getTenantsArray()) { log.info("Start tiers configuration migration for tenant " + tenant.getId() + '(' + tenant.getDomain() + ')'); try { registryService.startTenantFlow(tenant); if (!registryService.isGovernanceRegistryResourceExists(APIConstants.API_TIER_LOCATION)) { if (log.isDebugEnabled()) { log.debug("Tier resource does not exist for tenant " + tenant.getId() + '(' + tenant.getDomain() + ')'); } continue; } else { String apiTiers = ResourceUtil.getResourceContent( registryService.getGovernanceRegistryResource(APIConstants.API_TIER_LOCATION)); String updatedApiTiers = ResourceModifier.modifyTiers(apiTiers, APIConstants.API_TIER_LOCATION); registryService.updateGovernanceRegistryResource(APIConstants.API_TIER_LOCATION, updatedApiTiers); } // Since API tiers.xml has been updated it will be used as app and resource tier.xml // We do not care whether there is an already existing file in this location. Theoretically it should // not. If there was, then we override that file too. String apiTiers = ResourceUtil.getResourceContent( registryService.getGovernanceRegistryResource(APIConstants.API_TIER_LOCATION)); registryService.addGovernanceRegistryResource(APIConstants.APP_TIER_LOCATION, apiTiers, "application/xml"); registryService.addGovernanceRegistryResource(APIConstants.RES_TIER_LOCATION, apiTiers, "application/xml"); } catch (UserStoreException e) { log.error("Error occurred while accessing the user store " + +tenant.getId() + '(' + tenant.getDomain() + ')', e); } catch (RegistryException e) { log.error("Error occurred while accessing the registry " + +tenant.getId() + '(' + tenant.getDomain() + ')', e); } finally { registryService.endTenantFlow(); } log.info("End tiers configuration migration for tenant " + tenant.getId() + '(' + tenant.getDomain() + ')'); } log.info("Tiers configuration migration for API Manager completed."); } private void migrateLifeCycles() throws APIMigrationException { log.info("Life Cycles executor migration for API Manager started."); String apiLifeCycleXMLPath = CarbonUtils.getCarbonHome() + File.separator + APIConstants.RESOURCE_FOLDER_LOCATION + File.separator + Constants.LIFE_CYCLES_FOLDER + File.separator + APIConstants.API_LIFE_CYCLE + ".xml"; String executorlessApiLifeCycle = null; String apiLifeCycle = null; try (FileInputStream fileInputStream = new FileInputStream(new File(apiLifeCycleXMLPath))) { apiLifeCycle = IOUtils.toString(fileInputStream); executorlessApiLifeCycle = ResourceModifier.removeExecutorsFromAPILifeCycle(apiLifeCycle); } catch (FileNotFoundException e) { ResourceUtil.handleException("File " + apiLifeCycleXMLPath + " not found", e); } catch (IOException e) { ResourceUtil.handleException("Error reading file " + apiLifeCycleXMLPath, e); } final String apiLifeCycleRegistryPath = RegistryConstants.LIFECYCLE_CONFIGURATION_PATH + APIConstants.API_LIFE_CYCLE; for (Tenant tenant : getTenantsArray()) { log.info("Start life cycle migration for tenant " + tenant.getId() + '(' + tenant.getDomain() + ')'); try { registryService.startTenantFlow(tenant); addExecutorlessLifeCycle(tenant, apiLifeCycleRegistryPath, executorlessApiLifeCycle); updateApiLifeCycleStatus(tenant); updateWithCompleteLifeCycle(tenant, apiLifeCycleRegistryPath, apiLifeCycle); } finally { registryService.endTenantFlow(); } log.info("End life cycle migration for tenant " + tenant.getId() + '(' + tenant.getDomain() + ')'); } log.info("Life Cycles executor migration for API Manager completed."); } private void addExecutorlessLifeCycle(Tenant tenant, String apiLifeCycleRegistryPath, String executorlessApiLifeCycle) throws APIMigrationException { try { if (log.isDebugEnabled()) { log.debug("Adding executorless LC for tenant " + tenant.getId() + '(' + tenant.getDomain() + ')'); } if (!registryService.isConfigRegistryResourceExists(apiLifeCycleRegistryPath)) { registryService.addConfigRegistryResource(apiLifeCycleRegistryPath, executorlessApiLifeCycle, "application/xml"); } else { registryService.updateConfigRegistryResource(apiLifeCycleRegistryPath, executorlessApiLifeCycle); } if (log.isDebugEnabled()) { log.debug("Completed adding executorless LC for tenant " + tenant.getId() + '(' + tenant.getDomain() + ')'); } } catch (UserStoreException e) { log.error("Error occurred while accessing the user store when adding executorless " + APIConstants.API_LIFE_CYCLE + " for tenant " + tenant.getId() + '(' + tenant.getDomain() + ')', e); } catch (RegistryException e) { log.error("Error occurred while accessing the registry when adding executorless " + APIConstants.API_LIFE_CYCLE + " for tenant " + tenant.getId() + '(' + tenant.getDomain() + ')', e); } } private void updateApiLifeCycleStatus(Tenant tenant) throws APIMigrationException { HashMap<String, String[]> statuses = new HashMap<>(); statuses.put(APIStatus.PUBLISHED.toString(), new String[] { "Publish" }); statuses.put(APIStatus.PROTOTYPED.toString(), new String[] { "Deploy as a Prototype" }); statuses.put(APIStatus.BLOCKED.toString(), new String[] { "Publish", "Block" }); statuses.put(APIStatus.DEPRECATED.toString(), new String[] { "Publish", "Deprecate" }); statuses.put(APIStatus.RETIRED.toString(), new String[] { "Publish", "Deprecate", "Retire" }); if (log.isDebugEnabled()) { log.debug("Updating LC status for tenant " + tenant.getId() + '(' + tenant.getDomain() + ')'); } try { registryService.addDefaultLifecycles(); GenericArtifact[] artifacts = registryService.getGenericAPIArtifacts(); for (GenericArtifact artifact : artifacts) { try { String currentState = artifact.getAttribute(APIConstants.API_OVERVIEW_STATUS); //Check whether API is already migrated if (currentState != null && !currentState.equalsIgnoreCase(artifact.getLifecycleState())) { artifact.attachLifecycle(APIConstants.API_LIFE_CYCLE); String[] actions = statuses.get(currentState); if (actions != null) { for (String action : actions) { artifact.invokeAction(action, APIConstants.API_LIFE_CYCLE); if (log.isDebugEnabled()) { log.debug("Target LC Status : " + currentState + ". Performing LC Action : " + action); } } } } else { log.info("API is already in target LC state: " + currentState + ". Skipping migration for API " + artifact.getAttribute(APIConstants.API_OVERVIEW_NAME)); } } catch (GovernanceException e) { // Log the error and continue to the next governance artifact. log.error("Unable to update the lifecycle state of artifact ", e); } } if (log.isDebugEnabled()) { log.debug("Completed updating LC status for tenant " + tenant.getId() + '(' + tenant.getDomain() + ')'); } } catch (RegistryException e) { log.error("Error occurred while accessing the registry when updating " + "API life cycles for tenant " + tenant.getId() + '(' + tenant.getDomain() + ')', e); } catch (XMLStreamException e) { log.error("XMLStreamException while adding default life cycles if " + "not available for tenant " + tenant.getId() + '(' + tenant.getDomain() + ')', e); } catch (FileNotFoundException e) { log.error("FileNotFoundException while adding default life cycles if " + "not available for tenant " + tenant.getId() + '(' + tenant.getDomain() + ')', e); } catch (UserStoreException e) { log.error("UserStoreException while adding default life cycles if " + "not available for tenant " + tenant.getId() + '(' + tenant.getDomain() + ')', e); } } private void updateWithCompleteLifeCycle(Tenant tenant, String apiLifeCycleRegistryPath, String apiLifeCycle) throws APIMigrationException { if (log.isDebugEnabled()) { log.debug("Update with complete LC for tenant " + tenant.getId() + '(' + tenant.getDomain() + ')'); } try { registryService.updateConfigRegistryResource(apiLifeCycleRegistryPath, apiLifeCycle); if (log.isDebugEnabled()) { log.debug("Completed update with complete LC for tenant " + tenant.getId() + '(' + tenant.getDomain() + ')'); } } catch (UserStoreException e) { log.error("Error occurred while accessing the user store when adding complete " + APIConstants.API_LIFE_CYCLE + " for tenant " + tenant.getId() + '(' + tenant.getDomain() + ')', e); } catch (RegistryException e) { log.error("Error occurred while accessing the registry when adding complete " + APIConstants.API_LIFE_CYCLE + " for tenant " + tenant.getId() + '(' + tenant.getDomain() + ')', e); } } }