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 apim.restful.importexport.utils; import apim.restful.importexport.APIExportException; import apim.restful.importexport.APIImportExportConstants; import apim.restful.importexport.APIImportException; import apim.restful.importexport.APIService; import com.google.common.collect.Sets; import com.google.gson.Gson; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonParser; import org.apache.axiom.om.OMElement; import org.apache.commons.io.FileUtils; import org.apache.commons.io.FilenameUtils; import org.apache.commons.io.IOUtils; 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.*; 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; import org.wso2.carbon.registry.core.RegistryConstants; import org.wso2.carbon.registry.core.Resource; import javax.xml.namespace.QName; import java.io.BufferedInputStream; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.InputStreamReader; import java.io.InputStream; import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; import java.net.URLConnection; import java.util.Enumeration; import java.util.Set; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; /** * This class provides the functions utilized to import an API from an API archive. */ public final class APIImportUtil { private static final Log log = LogFactory.getLog(APIService.class); static APIProvider provider; /** * This method initializes the Provider when there is a direct request to import an API * * @param currentUserName the current logged in user * @throws APIExportException if provider cannot be initialized */ public static void initializeProvider(String currentUserName) throws APIExportException { provider = APIExportUtil.getProvider(currentUserName); } /** * This method uploads a given file to specified location * * @param uploadedInputStream input stream of the file * @param newFileName name of the file to be created * @param storageLocation destination of the new file * @throws APIImportException if the file transfer fails */ public static void transferFile(InputStream uploadedInputStream, String newFileName, String storageLocation) throws APIImportException { FileOutputStream outFileStream = null; try { outFileStream = new FileOutputStream(new File(storageLocation, newFileName)); int read = 0; byte[] bytes = new byte[1024]; while ((read = uploadedInputStream.read(bytes)) != -1) { outFileStream.write(bytes, 0, read); } } catch (IOException e) { log.error("Error in transferring files.", e); throw new APIImportException("Error in transferring archive files. " + e.getMessage()); } finally { IOUtils.closeQuietly(outFileStream); } } /** * This method decompresses API the archive * * @param sourceFile The archive containing the API * @param destination location of the archive to be extracted * @return Name of the extracted directory * @throws APIImportException If the decompressing fails */ public static String extractArchive(File sourceFile, String destination) throws APIImportException { BufferedInputStream inputStream = null; InputStream zipInputStream = null; FileOutputStream outputStream = null; ZipFile zip = null; String archiveName = null; try { zip = new ZipFile(sourceFile); Enumeration zipFileEntries = zip.entries(); int index = 0; // Process each entry while (zipFileEntries.hasMoreElements()) { // grab a zip file entry ZipEntry entry = (ZipEntry) zipFileEntries.nextElement(); String currentEntry = entry.getName(); //This index variable is used to get the extracted folder name; that is root directory if (index == 0) { archiveName = currentEntry.substring(0, currentEntry.indexOf(APIImportExportConstants.ARCHIVE_PATH_SEPARATOR)); --index; } File destinationFile = new File(destination, currentEntry); File destinationParent = destinationFile.getParentFile(); // create the parent directory structure if (destinationParent.mkdirs()) { log.info("Creation of folder is successful. Directory Name : " + destinationParent.getName()); } if (!entry.isDirectory()) { zipInputStream = zip.getInputStream(entry); inputStream = new BufferedInputStream(zipInputStream); // write the current file to the destination outputStream = new FileOutputStream(destinationFile); IOUtils.copy(inputStream, outputStream); } } return archiveName; } catch (IOException e) { log.error("Failed to extract archive file ", e); throw new APIImportException("Failed to extract archive file. " + e.getMessage()); } finally { IOUtils.closeQuietly(zipInputStream); IOUtils.closeQuietly(inputStream); IOUtils.closeQuietly(outputStream); } } /** * This method imports an API * * @param pathToArchive location of the extracted folder of the API * @param currentUser the current logged in user * @param isDefaultProviderAllowed decision to keep or replace the provider * @throws APIImportException if there is an error in importing an API */ public static void importAPI(String pathToArchive, String currentUser, boolean isDefaultProviderAllowed) throws APIImportException { API importedApi; // If the original provider is preserved, if (isDefaultProviderAllowed) { FileInputStream inputStream = null; BufferedReader bufferedReader = null; try { inputStream = new FileInputStream(pathToArchive + APIImportExportConstants.JSON_FILE_LOCATION); bufferedReader = new BufferedReader(new InputStreamReader(inputStream)); importedApi = new Gson().fromJson(bufferedReader, API.class); } catch (FileNotFoundException e) { log.error("Error in locating api.json file. ", e); throw new APIImportException("Error in locating api.json file. " + e.getMessage()); } finally { IOUtils.closeQuietly(inputStream); IOUtils.closeQuietly(bufferedReader); } } else { String pathToJSONFile = pathToArchive + APIImportExportConstants.JSON_FILE_LOCATION; try { String jsonContent = FileUtils.readFileToString(new File(pathToJSONFile)); JsonElement configElement = new JsonParser().parse(jsonContent); JsonObject configObject = configElement.getAsJsonObject(); //locate the "providerName" within the "id" and set it as the current user JsonObject apiId = configObject.getAsJsonObject(APIImportExportConstants.ID_ELEMENT); apiId.addProperty(APIImportExportConstants.PROVIDER_ELEMENT, APIUtil.replaceEmailDomain(currentUser)); importedApi = new Gson().fromJson(configElement, API.class); } catch (IOException e) { log.error("Error in setting API provider to logged in user. ", e); throw new APIImportException("Error in setting API provider to logged in user. " + e.getMessage()); } } Set<Tier> allowedTiers; Set<Tier> unsupportedTiersList; try { allowedTiers = provider.getTiers(); } catch (APIManagementException e) { log.error("Error in retrieving tiers of the provider. ", e); throw new APIImportException("Error in retrieving tiers of the provider. " + e.getMessage()); } if (!(allowedTiers.isEmpty())) { unsupportedTiersList = Sets.difference(importedApi.getAvailableTiers(), allowedTiers); //If at least one unsupported tier is found, it should be removed before adding API if (!(unsupportedTiersList.isEmpty())) { for (Tier unsupportedTier : unsupportedTiersList) { //Process is continued with a warning and only supported tiers are added to the importer API log.warn("Tier name : " + unsupportedTier.getName() + " is not supported."); } //Remove the unsupported tiers before adding the API importedApi.removeAvailableTiers(unsupportedTiersList); } } try { int tenantId = APIUtil.getTenantId(currentUser); provider.addAPI(importedApi); 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); addAPISequences(pathToArchive, importedApi, currentUser); addAPIWsdl(pathToArchive, importedApi, currentUser); } /** * This method adds the icon to the API which is to be displayed at the API store. * * @param pathToArchive location of the extracted folder of the API * @param importedApi the imported API object */ private static void addAPIImage(String pathToArchive, API importedApi) { //Adding image icon to the API if there is any File imageFolder = new File(pathToArchive + APIImportExportConstants.IMAGE_FILE_LOCATION); File[] fileArray = imageFolder.listFiles(); FileInputStream inputStream = null; try { if (imageFolder.isDirectory() && fileArray != null) { //This loop locates the icon of the API for (File imageFile : fileArray) { if (imageFile != null && imageFile.getName().contains(APIImportExportConstants.IMAGE_FILE_NAME)) { String mimeType = URLConnection.guessContentTypeFromName(imageFile.getName()); inputStream = new FileInputStream(imageFile.getAbsolutePath()); Icon apiImage = new Icon(inputStream, mimeType); String thumbPath = APIUtil.getIconPath(importedApi.getId()); String thumbnailUrl = provider.addIcon(thumbPath, apiImage); importedApi.setThumbnailUrl( APIUtil.prependTenantPrefix(thumbnailUrl, importedApi.getId().getProviderName())); APIUtil.setResourcePermissions(importedApi.getId().getProviderName(), null, null, thumbPath); provider.updateAPI(importedApi); //the loop is terminated after successfully locating the icon break; } } } } catch (FileNotFoundException e) { //This is logged and process is continued because icon is optional for an API log.error("Icon for API is not found. ", e); } catch (APIManagementException e) { //This is logged and process is continued because icon is optional for an API log.error("Failed to add icon to the API. ", e); } catch (FaultGatewaysException e) { //This is logged and process is continued because icon is optional for an API log.error("Failed to update API after adding icon. ", e); } finally { IOUtils.closeQuietly(inputStream); } } /** * This method adds the documents to the imported API * * @param pathToArchive location of the extracted folder of the API * @param importedApi the imported API object */ private static void addAPIDocuments(String pathToArchive, API importedApi) { String docFileLocation = pathToArchive + APIImportExportConstants.DOCUMENT_FILE_LOCATION; FileInputStream inputStream = null; BufferedReader bufferedReader = null; APIIdentifier apiIdentifier = importedApi.getId(); try { if (checkFileExistence(docFileLocation)) { inputStream = new FileInputStream(docFileLocation); bufferedReader = new BufferedReader(new InputStreamReader(inputStream)); Documentation[] documentations = new Gson().fromJson(bufferedReader, Documentation[].class); //For each type of document separate action is performed for (Documentation doc : documentations) { if (APIImportExportConstants.INLINE_DOC_TYPE.equalsIgnoreCase(doc.getSourceType().toString())) { provider.addDocumentation(apiIdentifier, doc); provider.addDocumentationContent(importedApi, doc.getName(), doc.getSummary()); } else if (APIImportExportConstants.URL_DOC_TYPE .equalsIgnoreCase(doc.getSourceType().toString())) { provider.addDocumentation(apiIdentifier, doc); } else if (APIImportExportConstants.FILE_DOC_TYPE .equalsIgnoreCase(doc.getSourceType().toString())) { inputStream = new FileInputStream(pathToArchive + doc.getFilePath()); String docExtension = FilenameUtils.getExtension(pathToArchive + doc.getFilePath()); Icon apiDocument = new Icon(inputStream, docExtension); String visibleRolesList = importedApi.getVisibleRoles(); String[] visibleRoles = new String[0]; if (visibleRolesList != null) { visibleRoles = visibleRolesList.split(","); } String filePathDoc = APIUtil.getDocumentationFilePath(apiIdentifier, doc.getName()); APIUtil.setResourcePermissions(importedApi.getId().getProviderName(), importedApi.getVisibility(), visibleRoles, filePathDoc); doc.setFilePath(provider.addIcon(filePathDoc, apiDocument)); provider.addDocumentation(apiIdentifier, doc); } } } } catch (FileNotFoundException e) { //this error is logged and ignored because documents are optional in an API log.error("Failed to locate the document files of the API.", e); } catch (APIManagementException e) { //this error is logged and ignored because documents are optional in an API log.error("Failed to add Documentations to API.", e); } finally { IOUtils.closeQuietly(inputStream); IOUtils.closeQuietly(bufferedReader); } } /** * This method adds API sequences to the imported API. If the sequence is a newly defined one, it is added. * * @param pathToArchive location of the extracted folder of the API * @param importedApi the imported API object * @param currentUser current logged in username */ private static void addAPISequences(String pathToArchive, API importedApi, String currentUser) { Registry registry = APIExportUtil.getRegistry(currentUser); //Adding in-sequence, if any String inSequenceName = importedApi.getInSequence(); if (inSequenceName != null && !inSequenceName.isEmpty()) { importAPISequence(inSequenceName, registry, APIConstants.API_CUSTOM_SEQUENCE_TYPE_IN, pathToArchive, APIImportExportConstants.IN_SEQUENCE_LOCATION); } //Adding out-sequence, if any String outSequenceName = importedApi.getOutSequence(); if (outSequenceName != null && !outSequenceName.isEmpty()) { importAPISequence(outSequenceName, registry, APIConstants.API_CUSTOM_SEQUENCE_TYPE_OUT, pathToArchive, APIImportExportConstants.OUT_SEQUENCE_LOCATION); } //Adding fault-sequence, if any String faultSequenceName = importedApi.getFaultSequence(); if (faultSequenceName != null && !faultSequenceName.isEmpty()) { importAPISequence(faultSequenceName, registry, APIConstants.API_CUSTOM_SEQUENCE_TYPE_FAULT, pathToArchive, APIImportExportConstants.FAULT_SEQUENCE_LOCATION); } } /** * Import custom sequences * * @param sequenceName Name of the sequence * @param registry Tenant registry * @param direction Direction of the sequence * @param pathToArchive Location of the extracted folder of the imported APi archive */ private static void importAPISequence(String sequenceName, Registry registry, String direction, String pathToArchive, String sequenceLocation) { String sequenceFileLocation = pathToArchive + sequenceLocation; File sequenceFileFolder = new File(sequenceFileLocation); File[] fileList = sequenceFileFolder.listFiles(); String sequenceFileName; InputStream fileInputStream = null; for (final File fileEntry : fileList) { if (fileEntry.isFile()) { try { fileInputStream = new FileInputStream(fileEntry); OMElement seqElement = APIUtil.buildOMElement(fileInputStream); if (sequenceName.equals(seqElement.getAttributeValue(new QName("name")))) { sequenceFileName = FilenameUtils.getName(fileEntry.getName()); addSequenceToRegistry(registry, direction, sequenceFileName, sequenceFileLocation + sequenceFileName); } } catch (Exception e) { //this error is logged and ignored because sequences are optional in an API log.error("Failed to retrieve Sequence of imported API.", e); } finally { IOUtils.closeQuietly(fileInputStream); } } } } /** * This method adds the sequence files to the registry. * * @param registry the registry instance * @param customSequenceType type of the sequence * @param sequenceFileName name of the sequence * @param sequenceFileLocation location of the sequence file */ private static void addSequenceToRegistry(Registry registry, String customSequenceType, String sequenceFileName, String sequenceFileLocation) { String regResourcePath = APIConstants.API_CUSTOM_SEQUENCE_LOCATION + RegistryConstants.PATH_SEPARATOR + customSequenceType + RegistryConstants.PATH_SEPARATOR + sequenceFileName; InputStream inSeqStream = null; try { if (registry.resourceExists(regResourcePath)) { if (log.isDebugEnabled()) { log.debug("Defined sequences have already been added to the registry"); } } else { if (log.isDebugEnabled()) { log.debug("Adding defined sequences to the registry."); } File sequenceFile = new File(sequenceFileLocation); inSeqStream = new FileInputStream(sequenceFile); byte[] inSeqData = IOUtils.toByteArray(inSeqStream); Resource inSeqResource = (Resource) registry.newResource(); inSeqResource.setContent(inSeqData); registry.put(regResourcePath, inSeqResource); } } catch (org.wso2.carbon.registry.api.RegistryException e) { //this is logged and ignored because sequences are optional log.error("Failed to add sequences into the registry: " + customSequenceType, e); } catch (IOException e) { //this is logged and ignored because sequences are optional log.error("I/O error while writing sequence data to the registry, Sequence type: " + customSequenceType, e); } finally { IOUtils.closeQuietly(inSeqStream); } } /** * This method adds the WSDL to the registry, if there is a WSDL associated with the API * * @param pathToArchive location of the extracted folder of the API * @param importedApi the imported API object * @param currentUser current logged in username */ private static void addAPIWsdl(String pathToArchive, API importedApi, String currentUser) { String wsdlFileName = importedApi.getId().getApiName() + "-" + importedApi.getId().getVersion() + APIImportExportConstants.WSDL_EXTENSION; String wsdlPath = pathToArchive + APIImportExportConstants.WSDL_LOCATION + wsdlFileName; if (checkFileExistence(wsdlPath)) { try { URL wsdlFileUrl = new File(wsdlPath).toURI().toURL(); importedApi.setWsdlUrl(wsdlFileUrl.toString()); Registry registry = APIExportUtil.getRegistry(currentUser); APIUtil.createWSDL((org.wso2.carbon.registry.core.Registry) registry, importedApi); } catch (MalformedURLException e) { //this exception is logged and ignored since WSDL is optional for an API log.error("Error in getting WSDL URL. ", e); } catch (org.wso2.carbon.registry.core.exceptions.RegistryException e) { //this exception is logged and ignored since WSDL is optional for an API log.error("Error in putting the WSDL resource to registry. ", e); } catch (APIManagementException e) { //this exception is logged and ignored since WSDL is optional for an API log.error("Error in creating the WSDL resource in the registry. ", e); } } } /** * This method adds Swagger API definition to registry * * @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(API importedApi, String archivePath, int tenantId) throws APIImportException { try { String swaggerContent = FileUtils .readFileToString(new File(archivePath + APIImportExportConstants.SWAGGER_DEFINITION_LOCATION)); 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<URITemplate> uriTemplates = definitionFromSwagger20.getURITemplates(importedApi, swaggerContent); //retrieve scopes Set<Scope> 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 * * @param fileLocation location of the file * @return true if the file exists, false otherwise */ private static boolean checkFileExistence(String fileLocation) { File testFile = new File(fileLocation); return testFile.exists(); } }