Skip to content

Commit

Permalink
Support import/export SOAPToREST APIs with custom mediation policies
Browse files Browse the repository at this point in the history
  • Loading branch information
chamilaadhi committed May 30, 2024
1 parent bb09c58 commit 2bc31ee
Show file tree
Hide file tree
Showing 7 changed files with 215 additions and 14 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -1908,4 +1908,14 @@ boolean isPolicyMetadataExists(String gatewayPolicyMappingId)
* @throws APIManagementException
*/
int getPolicyUsageByPolicyUUIDInGatewayPolicies(String commonPolicyUUID) throws APIManagementException;

/**
* Update SoapToRest Sequences for the given API.
* @param organization Organization
* @param apiId API ID
* @param sequences list of SOAPToRestSequence.
* @throws APIPersistenceException
*/
void updateSoapToRestSequences(String organization, String apiId, List<SOAPToRestSequence> sequences)
throws APIManagementException;
}
Original file line number Diff line number Diff line change
Expand Up @@ -7255,5 +7255,15 @@ private Map<String, Set<String>> getGatewayPolicyDeploymentMap(List<GatewayPolic
}
}
return gatewayPolicyDeploymentMapForResponse;

@Override
public void updateSoapToRestSequences(String organization, String apiId, List<SOAPToRestSequence> sequences)
throws APIManagementException {
Organization org = new Organization(organization);
try {
apiPersistenceInstance.updateSoapToRestSequences(org, apiId, sequences);
} catch (APIPersistenceException e) {
throw new APIManagementException("Error while sequences to the api " + apiId, e);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
package org.wso2.carbon.apimgt.persistence;

import org.wso2.carbon.apimgt.api.APIManagementException;
import org.wso2.carbon.apimgt.api.model.SOAPToRestSequence;
import org.wso2.carbon.apimgt.api.model.Tag;
import org.wso2.carbon.apimgt.persistence.dto.AdminContentSearchResult;
import org.wso2.carbon.apimgt.persistence.dto.DevPortalAPI;
Expand Down Expand Up @@ -519,6 +520,16 @@ PublisherAPIProductSearchResult searchAPIProductsForPublisher(Organization org,
* @return list of all the tags of an organization
*/
Set<Tag> getAllTags(Organization org, UserContext ctx) throws APIPersistenceException;

/**
* Update SoapToRest Sequences for the given API.
* @param org Organization the API product is owned by
* @param apiId API ID
* @param sequences list of SOAPToRestSequence.
* @throws APIPersistenceException
*/
void updateSoapToRestSequences(Organization org, String apiId, List<SOAPToRestSequence> sequences)
throws APIPersistenceException;

void changeApiProvider(String providerName, String apiId, String org) throws APIManagementException,
APIPersistenceException;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@
import org.wso2.carbon.apimgt.api.APIMgtResourceNotFoundException;
import org.wso2.carbon.apimgt.api.ExceptionCodes;
import org.wso2.carbon.apimgt.api.model.*;
import org.wso2.carbon.apimgt.api.model.Tag;
import org.wso2.carbon.apimgt.api.model.SOAPToRestSequence.Direction;
import org.wso2.carbon.apimgt.persistence.dto.*;
import org.wso2.carbon.apimgt.persistence.dto.Documentation;
Expand Down Expand Up @@ -3920,4 +3919,77 @@ public AdminContentSearchResult searchContentForAdmin(String org, String searchQ
return result;
}

public void updateSoapToRestSequences(Organization org, String apiId, List<SOAPToRestSequence> sequences)
throws APIPersistenceException {

boolean transactionCommitted = false;
boolean tenantFlowStarted = false;
Registry registry = null;
try {
RegistryHolder holder = getRegistry(org.getName());
registry = holder.getRegistry();
tenantFlowStarted = holder.isTenantFlowStarted();
registry.beginTransaction();
GenericArtifact artifact = getAPIArtifact(apiId, registry);

for (SOAPToRestSequence soapToRestSequence : sequences) {

String apiResourceName = soapToRestSequence.getPath();
if (apiResourceName.startsWith("/")) {
apiResourceName = apiResourceName.substring(1);
}
String resourcePath = APIConstants.API_ROOT_LOCATION + RegistryConstants.PATH_SEPARATOR
+ RegistryPersistenceUtil
.replaceEmailDomain(artifact.getAttribute(APIConstants.API_OVERVIEW_PROVIDER))
+ RegistryConstants.PATH_SEPARATOR + artifact.getAttribute(APIConstants.API_OVERVIEW_NAME)
+ RegistryConstants.PATH_SEPARATOR + artifact.getAttribute(APIConstants.API_OVERVIEW_VERSION)
+ RegistryConstants.PATH_SEPARATOR;
if (soapToRestSequence.getDirection() == Direction.OUT) {
resourcePath = resourcePath + "soap_to_rest" + RegistryConstants.PATH_SEPARATOR + "out"
+ RegistryConstants.PATH_SEPARATOR;
} else {
resourcePath = resourcePath + "soap_to_rest" + RegistryConstants.PATH_SEPARATOR + "in"
+ RegistryConstants.PATH_SEPARATOR;
}
resourcePath = resourcePath + apiResourceName + "_" + soapToRestSequence.getMethod() + ".xml";

Resource regResource;
if (!registry.resourceExists(resourcePath)) {
regResource = registry.newResource();
} else {
regResource = registry.get(resourcePath);
}
regResource.setContent(soapToRestSequence.getContent());
regResource.addProperty("method", soapToRestSequence.getMethod());
if (regResource.getProperty("resourcePath") != null) {
regResource.removeProperty("resourcePath");
}
regResource.addProperty("resourcePath", apiResourceName);
regResource.setMediaType("text/xml");
registry.put(resourcePath, regResource);
}
registry.commitTransaction();
transactionCommitted = true;
} catch (Exception e) {
try {
registry.rollbackTransaction();
} catch (RegistryException re) {
// Throwing an error from this level will mask the original exception
log.error("Error while rolling back the transaction for API: " + apiId, re);
}
throw new APIPersistenceException("Error while performing registry transaction operation ", e);
} finally {
if (tenantFlowStarted) {
RegistryPersistenceUtil.endTenantFlow();
}
try {
if (registry != null && !transactionCommitted) {
registry.rollbackTransaction();
}
} catch (RegistryException ex) {
log.error("Error occurred while rolling back the transaction.", ex);
}
}

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -194,11 +194,11 @@ public static File exportApi(APIProvider apiProvider, APIIdentifier apiIdentifie
addThumbnailToArchive(archivePath, apiIdentifier, apiProvider);
addDocumentationToArchive(archivePath, apiIdentifier, exportFormat, apiProvider,
APIConstants.API_IDENTIFIER_TYPE);
} else {
if (StringUtils.equals(apiDtoToReturn.getType().toString().toLowerCase(),
APIConstants.API_TYPE_SOAPTOREST.toLowerCase())) {
addSOAPToRESTMediationToArchive(archivePath, api);
}
}

if (StringUtils.equals(apiDtoToReturn.getType().toString().toLowerCase(),
APIConstants.API_TYPE_SOAPTOREST.toLowerCase())) {
addSOAPToRESTMediationToArchive(archivePath, api);
}

if (StringUtils
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@
import org.wso2.carbon.apimgt.api.model.OperationPolicyData;
import org.wso2.carbon.apimgt.api.model.OperationPolicyDefinition;
import org.wso2.carbon.apimgt.api.model.OperationPolicySpecification;
import org.wso2.carbon.apimgt.api.model.SOAPToRestSequence;
import org.wso2.carbon.apimgt.api.model.SOAPToRestSequence.Direction;
import org.wso2.carbon.apimgt.api.model.Scope;
import org.wso2.carbon.apimgt.api.model.URITemplate;
import org.wso2.carbon.apimgt.api.model.graphql.queryanalysis.GraphqlComplexityInfo;
Expand Down Expand Up @@ -330,7 +332,7 @@ public static ImportedAPIDTO importApi(String extractedFolderPath, APIDTO import
}
importedApi = PublisherCommonUtils.updateApiAndDefinition(targetApi, importedApiDTO,
RestApiCommonUtil.getLoggedInUserProvider(), tokenScopes,
validationResponse);
validationResponse, false);
} else {
if (targetApi == null && Boolean.TRUE.equals(overwrite)) {
log.info("Cannot find : " + importedApiDTO.getName() + "-" + importedApiDTO.getVersion()
Expand All @@ -348,7 +350,7 @@ public static ImportedAPIDTO importApi(String extractedFolderPath, APIDTO import
&& !APIConstants.APITransportType.GRAPHQL.toString().equalsIgnoreCase(apiType)) {
// Add the validated swagger separately since the UI does the same procedure
PublisherCommonUtils.updateSwagger(importedApi.getUuid(), validationResponse, false,
organization);
organization, false);
importedApi = apiProvider.getAPIbyUUID(importedApi.getUuid(), currentTenantDomain);
}
} else {
Expand Down Expand Up @@ -400,7 +402,11 @@ public static ImportedAPIDTO importApi(String extractedFolderPath, APIDTO import
}
if (StringUtils
.equals(importedApi.getType().toLowerCase(), APIConstants.API_TYPE_SOAPTOREST.toLowerCase())) {
addSOAPToREST(importedApi, validationResponse.getContent(), apiProvider);
List<SOAPToRestSequence> sequences = getSOAPToRESTSequences(extractedFolderPath);
if (sequences != null && !sequences.isEmpty()) {
String tenantDomain = RestApiCommonUtil.getLoggedInUserTenantDomain();
apiProvider.updateSoapToRestSequences(tenantDomain, importedApi.getUuid(), sequences);
}
}

if (!isAdvertiseOnlyAPI(importedApiDTO)) {
Expand Down Expand Up @@ -2321,7 +2327,58 @@ private static void addSOAPToREST(API importedApi, String swaggerContent, APIPro
PublisherCommonUtils
.updateAPIBySettingGenerateSequencesFromSwagger(swaggerContent, importedApi, apiProvider, tenantDomain);
}

/**
* This method retrieve soap to rest sequences from the exported zip file.
*
* @param extractedFolderPath folder path.
* @return List<SOAPToRestSequence> list of soap to rest sequences
* @throws APIManagementException
*/
private static List<SOAPToRestSequence> getSOAPToRESTSequences(String extractedFolderPath)
throws APIManagementException {

List<SOAPToRestSequence> list = new ArrayList<SOAPToRestSequence>();
try {
String folderName = extractedFolderPath + File.separator + SOAPTOREST;
String[] directions = { IN, OUT };
if (APIUtil.checkFileExistence(folderName)) {
for (int i = 0; i < directions.length; i++) {
String sequenceFolderName = folderName + File.separator + directions[i];
if (APIUtil.checkFileExistence(sequenceFolderName)) {
File sequenceFolder = new File(sequenceFolderName);
File[] listOfFiles = sequenceFolder.listFiles();
if (listOfFiles != null) {
for (File file : listOfFiles) {
if (file.isFile() && file.getName().endsWith(".xml")) {
if (log.isDebugEnabled()) {
log.debug("Found sequence " + file.getName() + " in " + sequenceFolder);
}
String operation = file.getName().replace(".xml", "");
// Find the last underscore in the string
int lastUnderscoreIndex = operation.lastIndexOf('_');
// Split the string from the last underscore
//String path = "/" + operation.substring(0, lastUnderscoreIndex);
String path = operation.substring(0, lastUnderscoreIndex);
String method = operation.substring(lastUnderscoreIndex + 1);
String content = FileUtils.readFileToString(file);
Direction direction = IN.equals(directions[i]) ? Direction.IN : Direction.OUT;
SOAPToRestSequence seq = new SOAPToRestSequence(method, path, content, direction);
list.add(seq);
}
}
}

}
}
}
} catch (IOException e) {
throw new APIManagementException("Error while reading sequences from path: " + extractedFolderPath, e,
ExceptionCodes.ERROR_READING_META_DATA);
}
return list;
}

public static List<SoapToRestMediationDto> retrieveSoapToRestFlowMediations(String pathToArchive, String type)
throws APIManagementException {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -133,12 +133,34 @@ public static API updateApiAndDefinition(API originalAPI, APIDTO apiDtoToUpdate,
String[] tokenScopes, APIDefinitionValidationResponse response)
throws APIManagementException, ParseException, CryptoException, FaultGatewaysException {

return updateApiAndDefinition(originalAPI, apiDtoToUpdate, apiProvider, tokenScopes, response, true);
}

/**
* Update API and API definition. Soap to rest sequence is updated on demand.
*
* @param originalAPI existing API
* @param apiDtoToUpdate DTO object with updated API data
* @param apiProvider API Provider
* @param tokenScopes token scopes
* @param generateSoapToRestSequences Option to generate soap to rest sequences.
* @param response response of the API definition validation
* @return updated API
* @throws APIManagementException If an error occurs while updating the API and API definition
* @throws ParseException If an error occurs while parsing the endpoint configuration
* @throws CryptoException If an error occurs while encrypting the secret key of API
* @throws FaultGatewaysException If an error occurs while updating manage of an existing API
*/
public static API updateApiAndDefinition(API originalAPI, APIDTO apiDtoToUpdate, APIProvider apiProvider,
String[] tokenScopes, APIDefinitionValidationResponse response, boolean generateSoapToRestSequences)
throws APIManagementException, ParseException, CryptoException, FaultGatewaysException {

API apiToUpdate = prepareForUpdateApi(originalAPI, apiDtoToUpdate, apiProvider, tokenScopes);
String organization = RestApiCommonUtil.getLoggedInUserTenantDomain();
if (!PublisherCommonUtils.isStreamingAPI(apiDtoToUpdate) && !APIConstants.APITransportType.GRAPHQL.toString()
.equalsIgnoreCase(apiDtoToUpdate.getType().toString())) {
prepareForUpdateSwagger(originalAPI.getUuid(), response, false, apiProvider, organization,
response.getParser(), apiToUpdate);
response.getParser(), apiToUpdate, generateSoapToRestSequences);
}
apiProvider.updateAPI(apiToUpdate, originalAPI);
return apiProvider.getAPIbyUUID(originalAPI.getUuid(), originalAPI.getOrganization());
Expand Down Expand Up @@ -1405,11 +1427,30 @@ public static String updateSwagger(String apiId, APIDefinitionValidationResponse
String organization)
throws APIManagementException, FaultGatewaysException {

return updateSwagger(apiId, response, isServiceAPI, organization, true);
}

/**
* update swagger definition of the given api. For Soap To Rest APIs, sequences are generated on demand.
*
* @param apiId API Id
* @param response response of a swagger definition validation call
* @param organization Organization Identifier
* @param generateSoapToRestSequences Option to generate soap to rest sequences.
* @return updated swagger definition
* @throws APIManagementException when error occurred updating swagger
* @throws FaultGatewaysException when error occurred publishing API to the gateway
*/
public static String updateSwagger(String apiId, APIDefinitionValidationResponse response, boolean isServiceAPI,
String organization, boolean generateSoapToRestSequences)
throws APIManagementException, FaultGatewaysException {

APIProvider apiProvider = RestApiCommonUtil.getLoggedInUserProvider();
//this will fail if user does not have access to the API or the API does not exist
API existingAPI = apiProvider.getAPIbyUUID(apiId, organization);
APIDefinition oasParser = response.getParser();
prepareForUpdateSwagger(apiId, response, isServiceAPI, apiProvider, organization, oasParser, existingAPI);
prepareForUpdateSwagger(apiId, response, isServiceAPI, apiProvider, organization, oasParser, existingAPI,
generateSoapToRestSequences);

//Update API is called to update URITemplates and scopes of the API
API unModifiedAPI = apiProvider.getAPIbyUUID(apiId, organization);
Expand All @@ -1418,7 +1459,7 @@ public static String updateSwagger(String apiId, APIDefinitionValidationResponse

//retrieves the updated swagger definition
String apiSwagger = apiProvider.getOpenAPIDefinition(apiId, organization); // TODO see why we need to get it
// instead of passing same
//instead of passing same
return oasParser.getOASDefinitionForPublisher(existingAPI, apiSwagger);
}

Expand All @@ -1436,7 +1477,7 @@ public static String updateSwagger(String apiId, APIDefinitionValidationResponse
*/
private static void prepareForUpdateSwagger(String apiId, APIDefinitionValidationResponse response,
boolean isServiceAPI, APIProvider apiProvider, String organization,
APIDefinition oasParser, API existingAPI)
APIDefinition oasParser, API existingAPI, boolean genSoapToRestSequence)
throws APIManagementException {

String apiDefinition = response.getJsonContent();
Expand All @@ -1445,7 +1486,7 @@ private static void prepareForUpdateSwagger(String apiId, APIDefinitionValidatio
} else {
apiDefinition = OASParserUtil.preProcess(apiDefinition);
}
if (APIConstants.API_TYPE_SOAPTOREST.equals(existingAPI.getType())) {
if (APIConstants.API_TYPE_SOAPTOREST.equals(existingAPI.getType()) && genSoapToRestSequence) {
List<SOAPToRestSequence> sequenceList = SequenceGenerator.generateSequencesFromSwagger(apiDefinition);
existingAPI.setSoapToRestSequences(sequenceList);
}
Expand Down

0 comments on commit 2bc31ee

Please sign in to comment.