diff --git a/modules/api-import-export/src/main/java/apim/restful/importexport/APIImportExportConstants.java b/modules/api-import-export/src/main/java/apim/restful/importexport/APIImportExportConstants.java index 38b0a1f645..3928ad67fa 100644 --- a/modules/api-import-export/src/main/java/apim/restful/importexport/APIImportExportConstants.java +++ b/modules/api-import-export/src/main/java/apim/restful/importexport/APIImportExportConstants.java @@ -35,6 +35,8 @@ public final class APIImportExportConstants { public static final String TEMP_DIR = "java.io.tmpdir"; //name of the uploaded zip file public static final String UPLOAD_FILE_NAME = "APIArchive.zip"; + //Always use '/' as archive path separator despite the OS dependent path separator + public static final char ARCHIVE_PATH_SEPARATOR = '/'; //location of the api JSON file public static final String JSON_FILE_LOCATION = DIRECTORY_SEPARATOR + "Meta-information" + DIRECTORY_SEPARATOR + "api.json"; diff --git a/modules/api-import-export/src/main/java/apim/restful/importexport/utils/APIExportUtil.java b/modules/api-import-export/src/main/java/apim/restful/importexport/utils/APIExportUtil.java index e26acf59f9..47004783fc 100644 --- a/modules/api-import-export/src/main/java/apim/restful/importexport/utils/APIExportUtil.java +++ b/modules/api-import-export/src/main/java/apim/restful/importexport/utils/APIExportUtil.java @@ -32,10 +32,7 @@ import org.wso2.carbon.apimgt.api.APIDefinition; import org.wso2.carbon.apimgt.api.APIManagementException; import org.wso2.carbon.apimgt.api.APIProvider; -import org.wso2.carbon.apimgt.api.model.API; -import org.wso2.carbon.apimgt.api.model.APIIdentifier; -import org.wso2.carbon.apimgt.api.model.APIStatus; -import org.wso2.carbon.apimgt.api.model.Documentation; +import org.wso2.carbon.apimgt.api.model.*; import org.wso2.carbon.apimgt.impl.APIConstants; import org.wso2.carbon.apimgt.impl.APIManagerFactory; import org.wso2.carbon.apimgt.impl.definitions.APIDefinitionFromSwagger20; @@ -64,10 +61,7 @@ import java.io.OutputStream; import java.io.StringReader; -import java.util.AbstractMap; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; /** * This is the util class which consists of all the functions for exporting API @@ -582,6 +576,8 @@ private static void exportMetaInformation(API apiToReturn, Registry registry) th apiToReturn.getId().getVersion()); createDirectory(archivePath + File.separator + "Meta-information"); + //Remove unnecessary data from exported Api + cleanApiDataToExport(apiToReturn); Gson gson = new GsonBuilder().setPrettyPrinting().create(); String apiInJson = gson.toJson(apiToReturn); @@ -605,6 +601,20 @@ private static void exportMetaInformation(API apiToReturn, Registry registry) th } } + /** + * Clean api by removing unnecessary details + * + * @param api api to be exported + */ + private static void cleanApiDataToExport(API api) { + // Thumbnail will be set according to the importing environment. Therefore current URL is removed + api.setThumbnailUrl(null); + // Swagger.json contains complete details about scopes and URI templates. Therefore scope and URI template + // details are removed from api.json + api.setScopes(new TreeSet()); + api.setUriTemplates(new TreeSet()); + } + /** * Write content to file * diff --git a/modules/api-import-export/src/main/java/apim/restful/importexport/utils/APIImportUtil.java b/modules/api-import-export/src/main/java/apim/restful/importexport/utils/APIImportUtil.java index d0850792b6..152e2a5aa3 100644 --- a/modules/api-import-export/src/main/java/apim/restful/importexport/utils/APIImportUtil.java +++ b/modules/api-import-export/src/main/java/apim/restful/importexport/utils/APIImportUtil.java @@ -36,15 +36,14 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.apimgt.api.APIDefinition; import org.wso2.carbon.apimgt.api.APIManagementException; import org.wso2.carbon.apimgt.api.APIProvider; import org.wso2.carbon.apimgt.api.FaultGatewaysException; -import org.wso2.carbon.apimgt.api.model.API; -import org.wso2.carbon.apimgt.api.model.APIIdentifier; -import org.wso2.carbon.apimgt.api.model.Documentation; -import org.wso2.carbon.apimgt.api.model.Icon; -import org.wso2.carbon.apimgt.api.model.Tier; +import org.wso2.carbon.apimgt.api.model.*; import org.wso2.carbon.apimgt.impl.APIConstants; +import org.wso2.carbon.apimgt.impl.definitions.APIDefinitionFromSwagger20; +import org.wso2.carbon.apimgt.impl.handlers.ScopesIssuer; import org.wso2.carbon.apimgt.impl.utils.APIUtil; import org.wso2.carbon.registry.api.Registry; @@ -146,7 +145,8 @@ public static String extractArchive(File sourceFile, String destination) throws //This index variable is used to get the extracted folder name; that is root directory if (index == 0) { - archiveName = currentEntry.substring(0, currentEntry.indexOf(File.separatorChar)); + archiveName = + currentEntry.substring(0, currentEntry.indexOf(APIImportExportConstants.ARCHIVE_PATH_SEPARATOR)); --index; } @@ -255,14 +255,14 @@ public static void importAPI(String pathToArchive, String currentUser, boolean i } try{ + int tenantId = APIUtil.getTenantId(currentUser); provider.addAPI(importedApi); - addSwaggerDefinition(importedApi.getId(), pathToArchive); + addSwaggerDefinition(importedApi, pathToArchive, tenantId); } catch (APIManagementException e){ //Error is logged and APIImportException is thrown because adding API and swagger are mandatory steps log.error("Error in adding API to the provider. ", e); throw new APIImportException("Error in adding API to the provider. " + e.getMessage()); } - //Since Image, documents, sequences and WSDL are optional, exceptions are logged and ignored in implementation addAPIImage(pathToArchive, importedApi); addAPIDocuments(pathToArchive, importedApi); @@ -528,26 +528,69 @@ private static void addAPIWsdl(String pathToArchive, API importedApi, String cur /** * This method adds Swagger API definition to registry * - * @param apiId Identifier of the imported API + * @param importedApi Imported API * @param archivePath File path where API archive stored + * @param tenantId Id of the current tenant * @throws APIImportException if there is an error occurs when adding Swagger definition */ - private static void addSwaggerDefinition(APIIdentifier apiId, String archivePath) + private static void addSwaggerDefinition(API importedApi, String archivePath, int tenantId) throws APIImportException { try { String swaggerContent = FileUtils.readFileToString( new File(archivePath + APIImportExportConstants.SWAGGER_DEFINITION_LOCATION)); - provider.saveSwagger20Definition(apiId, swaggerContent); + + updateApiResourcesFromSwagger(importedApi, swaggerContent, tenantId); + provider.updateAPI(importedApi); + provider.saveSwagger20Definition(importedApi.getId(), swaggerContent); } catch (APIManagementException e) { log.error("Error in adding Swagger definition for the API. ", e); throw new APIImportException("Error in adding Swagger definition for the API. " + e.getMessage()); } catch (IOException e) { log.error("Error in importing Swagger definition for the API. ", e); throw new APIImportException("Error in importing Swagger definition for the API. " + e.getMessage()); + } catch (FaultGatewaysException e) { + log.error("Failed to update API after adding resources and scopes. ", e); + throw new APIImportException("Failed to update API after adding resources and scopes. " + e.getMessage()); + } + } + + /** + * Add URI templates and scopes retrieved from swagger.json to the imported API + * @param importedApi Imported API + * @param swaggerContent Content of swagger.json + * @param tenantId Current tenant ID + * @throws APIManagementException If an error occurs while adding resources to the imported api + */ + private static void updateApiResourcesFromSwagger(API importedApi, String swaggerContent, int tenantId) + throws APIManagementException { + + APIDefinition definitionFromSwagger20 = new APIDefinitionFromSwagger20(); + //retrieve URI templates + Set uriTemplates = definitionFromSwagger20.getURITemplates(importedApi, swaggerContent); + + //retrieve scopes + Set scopes = definitionFromSwagger20.getScopes(String.valueOf(swaggerContent)); + + //Check whether scopes of importing api are already assigned by another API + //If so, import process gets halted by throwing an exception + for (Scope scope : scopes) { + if (scope != null && !(ScopesIssuer.getInstance().isWhiteListedScope(scope.getKey()))) { + if (provider.isScopeKeyExist(scope.getKey(), tenantId)) { + log.error("Unable to assign scope! " + scope.getKey() + " is already assigned by another API"); + provider.deleteAPI(importedApi.getId()); + throw new APIManagementException("Unable to assign scope! " + scope.getKey() + + " is already assigned by another API"); + } + } } + + //set URI templates and scopes to the imported API + importedApi.setUriTemplates(uriTemplates); + importedApi.setScopes(scopes); } + /** * This method checks whether a given file exists in a given location * diff --git a/modules/api-import-export/src/main/java/apim/restful/importexport/utils/ArchiveGeneratorUtil.java b/modules/api-import-export/src/main/java/apim/restful/importexport/utils/ArchiveGeneratorUtil.java index 4ac18fdd57..1c10a1bdc7 100644 --- a/modules/api-import-export/src/main/java/apim/restful/importexport/utils/ArchiveGeneratorUtil.java +++ b/modules/api-import-export/src/main/java/apim/restful/importexport/utils/ArchiveGeneratorUtil.java @@ -19,6 +19,7 @@ package apim.restful.importexport.utils; import apim.restful.importexport.APIExportException; +import apim.restful.importexport.APIImportExportConstants; import org.apache.commons.io.IOUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -127,6 +128,8 @@ private static void addToArchive(File directoryToZip, File file, ZipOutputStream // Get relative path from archive directory to the specific file String zipFilePath = file.getCanonicalPath() .substring(directoryToZip.getCanonicalPath().length() + 1, file.getCanonicalPath().length()); + if (File.separatorChar != '/') + zipFilePath = zipFilePath.replace(File.separatorChar, APIImportExportConstants.ARCHIVE_PATH_SEPARATOR); ZipEntry zipEntry = new ZipEntry(zipFilePath); zipOutputStream.putNextEntry(zipEntry);