/**
   * Creates endpoint element for REST service
   *
   * @param requestContext information about current request.
   * @param wadlElement wadl document.
   * @param version wadl version.
   * @return Endpoint Path.
   * @throws RegistryException If fails to create endpoint element.
   */
  private String createEndpointElement(
      RequestContext requestContext, OMElement wadlElement, String version)
      throws RegistryException {
    OMNamespace wadlNamespace = wadlElement.getNamespace();
    String wadlNamespaceURI = wadlNamespace.getNamespaceURI();
    String wadlNamespacePrefix = wadlNamespace.getPrefix();
    OMElement resourcesElement =
        wadlElement.getFirstChildWithName(
            new QName(wadlNamespaceURI, "resources", wadlNamespacePrefix));
    if (resourcesElement != null) {
      String endpointUrl = resourcesElement.getAttributeValue(new QName("base"));
      if (endpointUrl != null) {
        String endpointPath = EndpointUtils.deriveEndpointFromUrl(endpointUrl);
        String endpointName = EndpointUtils.deriveEndpointNameFromUrl(endpointUrl);
        String endpointContent =
            EndpointUtils.getEndpointContentWithOverview(
                endpointUrl, endpointPath, endpointName, version);
        OMElement endpointElement;
        try {
          endpointElement = AXIOMUtil.stringToOM(endpointContent);
        } catch (XMLStreamException e) {
          throw new RegistryException("Error in creating the endpoint element. ", e);
        }

        return RESTServiceUtils.addEndpointToRegistry(
            requestContext, endpointElement, endpointPath);
      } else {
        log.warn("Base path does not exist. endpoint creation may fail. ");
      }
    } else {
      log.warn("Resources element is null. ");
    }
    return null;
  }
  public String addWadlToRegistry(
      RequestContext requestContext, Resource resource, String resourcePath, boolean skipValidation)
      throws RegistryException {
    String wadlName = RegistryUtils.getResourceName(resourcePath);
    String version =
        requestContext.getResource().getProperty(RegistryConstants.VERSION_PARAMETER_NAME);

    if (version == null) {
      version = CommonConstants.WADL_VERSION_DEFAULT_VALUE;
      requestContext.getResource().setProperty(RegistryConstants.VERSION_PARAMETER_NAME, version);
    }

    OMElement wadlElement;
    String wadlContent;
    Object resourceContent = resource.getContent();
    if (resourceContent instanceof String) {
      wadlContent = (String) resourceContent;
    } else {
      wadlContent = new String((byte[]) resourceContent);
    }

    try {
      XMLStreamReader reader =
          XMLInputFactory.newInstance().createXMLStreamReader(new StringReader(wadlContent));
      StAXOMBuilder builder = new StAXOMBuilder(reader);
      wadlElement = builder.getDocumentElement();
    } catch (XMLStreamException e) {
      // This exception is unexpected because the WADL already validated
      String msg = "Unexpected error occured " + "while reading the WADL at " + resourcePath + ".";
      log.error(msg);
      throw new RegistryException(msg, e);
    }

    String wadlNamespace = wadlElement.getNamespace().getNamespaceURI();
    String namespaceSegment =
        CommonUtil.derivePathFragmentFromNamespace(wadlNamespace).replace("//", "/");
    String actualPath =
        getChrootedWadlLocation(requestContext.getRegistryContext())
            + namespaceSegment
            + version
            + "/"
            + wadlName;

    OMElement grammarsElement =
        wadlElement.getFirstChildWithName(new QName(wadlNamespace, "grammars"));

    if (StringUtils.isNotBlank(requestContext.getSourceURL())) {
      String uri = requestContext.getSourceURL();
      if (!skipValidation) {
        validateWADL(uri);
      }

      if (resource.getUUID() == null) {
        resource.setUUID(UUID.randomUUID().toString());
      }

      String wadlBaseUri = uri.substring(0, uri.lastIndexOf("/") + 1);
      if (grammarsElement != null) {
        // This is to avoid evaluating the grammars import when building AST
        grammarsElement.detach();
        wadlElement.addChild(resolveImports(grammarsElement, wadlBaseUri, version));
      }
    } else {
      if (!skipValidation) {
        File tempFile = null;
        BufferedWriter bufferedWriter = null;
        try {
          tempFile = File.createTempFile(wadlName, null);
          bufferedWriter = new BufferedWriter(new FileWriter(tempFile));
          bufferedWriter.write(wadlElement.toString());
          bufferedWriter.flush();
        } catch (IOException e) {
          String msg = "Error occurred while reading the WADL File";
          log.error(msg, e);
          throw new RegistryException(msg, e);
        } finally {
          if (bufferedWriter != null) {
            try {
              bufferedWriter.close();
            } catch (IOException e) {
              String msg = "Error occurred while closing File writer";
              log.warn(msg, e);
            }
          }
        }
        validateWADL(tempFile.toURI().toString());
        try {
          delete(tempFile);
        } catch (IOException e) {
          String msg =
              "An error occurred while deleting the temporary files from local file system.";
          log.warn(msg, e);
          throw new RegistryException(msg, e);
        }
      }

      if (grammarsElement != null) {
        grammarsElement = resolveImports(grammarsElement, null, version);
        wadlElement.addChild(grammarsElement);
      }
    }

    requestContext.setResourcePath(new ResourcePath(actualPath));
    if (resource.getProperty(CommonConstants.SOURCE_PROPERTY) == null) {
      resource.setProperty(CommonConstants.SOURCE_PROPERTY, CommonConstants.SOURCE_AUTO);
    }
    registry.put(actualPath, resource);
    addImportAssociations(actualPath);
    if (getCreateService()) {
      OMElement serviceElement =
          RESTServiceUtils.createRestServiceArtifact(
              wadlElement,
              wadlName,
              version,
              RegistryUtils.getRelativePath(requestContext.getRegistryContext(), actualPath));
      String servicePath = RESTServiceUtils.addServiceToRegistry(requestContext, serviceElement);
      registry.addAssociation(servicePath, actualPath, CommonConstants.DEPENDS);
      registry.addAssociation(actualPath, servicePath, CommonConstants.USED_BY);
      String endpointPath = createEndpointElement(requestContext, wadlElement, version);
      if (endpointPath != null) {
        registry.addAssociation(servicePath, endpointPath, CommonConstants.DEPENDS);
        registry.addAssociation(endpointPath, servicePath, CommonConstants.USED_BY);
      }
    }

    return resource.getPath();
  }
  public String importWADLToRegistry(
      RequestContext requestContext, String commonLocation, boolean skipValidation)
      throws RegistryException {

    ResourcePath resourcePath = requestContext.getResourcePath();
    String wadlName = RegistryUtils.getResourceName(resourcePath.getPath());
    String version =
        requestContext.getResource().getProperty(RegistryConstants.VERSION_PARAMETER_NAME);

    if (version == null) {
      version = CommonConstants.WADL_VERSION_DEFAULT_VALUE;
      requestContext.getResource().setProperty(RegistryConstants.VERSION_PARAMETER_NAME, version);
    }

    String uri = requestContext.getSourceURL();
    if (!skipValidation) {
      validateWADL(uri);
    }

    Registry registry = requestContext.getRegistry();
    Resource resource = registry.newResource();
    if (resource.getUUID() == null) {
      resource.setUUID(UUID.randomUUID().toString());
    }
    resource.setMediaType(wadlMediaType);
    resource.setProperties(requestContext.getResource().getProperties());

    ByteArrayOutputStream outputStream;
    OMElement wadlElement;
    try {
      InputStream inputStream = new URL(uri).openStream();

      outputStream = new ByteArrayOutputStream();
      int nextChar;
      while ((nextChar = inputStream.read()) != -1) {
        outputStream.write(nextChar);
      }
      outputStream.flush();
      wadlElement = AXIOMUtil.stringToOM(new String(outputStream.toByteArray()));
      // to validate XML
      wadlElement.toString();
    } catch (Exception e) {
      // This exception is unexpected because the WADL already validated
      throw new RegistryException(
          "Unexpected error occured " + "while reading the WADL at" + uri, e);
    }

    String wadlNamespace = wadlElement.getNamespace().getNamespaceURI();
    String namespaceSegment =
        CommonUtil.derivePathFragmentFromNamespace(wadlNamespace).replace("//", "/");

    OMElement grammarsElement =
        wadlElement.getFirstChildWithName(new QName(wadlNamespace, "grammars"));
    String wadlBaseUri = uri.substring(0, uri.lastIndexOf("/") + 1);
    if (grammarsElement != null) {
      grammarsElement.detach();
      wadlElement.addChild(resolveImports(grammarsElement, wadlBaseUri, version));
    }

    String actualPath;
    if (commonLocation != null) {
      actualPath = commonLocation + namespaceSegment + version + "/" + wadlName;
    } else {
      actualPath =
          RegistryConstants.GOVERNANCE_REGISTRY_BASE_PATH
              + commonWADLLocation
              + namespaceSegment
              + version
              + "/"
              + wadlName;
    }
    if (resource.getProperty(CommonConstants.SOURCE_PROPERTY) == null) {
      resource.setProperty(CommonConstants.SOURCE_PROPERTY, CommonConstants.SOURCE_AUTO);
    }

    resource.setContent(wadlElement.toString());
    requestContext.setResourcePath(new ResourcePath(actualPath));
    registry.put(actualPath, resource);
    addImportAssociations(actualPath);
    if (createService) {
      OMElement serviceElement =
          RESTServiceUtils.createRestServiceArtifact(
              wadlElement,
              wadlName,
              version,
              RegistryUtils.getRelativePath(requestContext.getRegistryContext(), actualPath));
      String servicePath = RESTServiceUtils.addServiceToRegistry(requestContext, serviceElement);
      addDependency(servicePath, actualPath);
      String endpointPath = createEndpointElement(requestContext, wadlElement, version);
      if (endpointPath != null) {
        addDependency(servicePath, endpointPath);
      }
    }

    return actualPath;
  }
  /**
   * Saves the swagger file as a registry artifact.
   *
   * @param inputStream input stream to read content.
   * @param commonLocation root location of the swagger artifacts.
   * @param sourceUrl source URL.
   * @throws RegistryException If a failure occurs when adding the swagger to registry.
   */
  public boolean processSwagger(InputStream inputStream, String commonLocation, String sourceUrl)
      throws RegistryException {
    // create a collection if not exists.
    createCollection(commonLocation);

    // Reading resource content and content details.
    ByteArrayOutputStream swaggerContentStream = CommonUtil.readSourceContent(inputStream);
    JsonObject swaggerDocObject = getSwaggerObject(swaggerContentStream.toString());
    String swaggerVersion = getSwaggerVersion(swaggerDocObject);
    documentVersion =
        requestContext.getResource().getProperty(RegistryConstants.VERSION_PARAMETER_NAME);
    if (documentVersion == null) {
      documentVersion = CommonConstants.SWAGGER_DOC_VERSION_DEFAULT_VALUE;
      requestContext
          .getResource()
          .setProperty(RegistryConstants.VERSION_PARAMETER_NAME, documentVersion);
    }
    String swaggerResourcePath = getSwaggerDocumentPath(commonLocation, swaggerDocObject);

    /*
    Switches from the swagger version and process document adding process and the REST Service creation process
    using the relevant documents.
     */
    if (SwaggerConstants.SWAGGER_VERSION_12.equals(swaggerVersion)) {
      if (addSwaggerDocumentToRegistry(
          swaggerContentStream, swaggerResourcePath, documentVersion)) {
        List<JsonObject> resourceObjects =
            addResourceDocsToRegistry(swaggerDocObject, sourceUrl, swaggerResourcePath);
        restServiceElement =
            (resourceObjects != null)
                ? RESTServiceUtils.createRestServiceArtifact(
                    swaggerDocObject,
                    swaggerVersion,
                    endpointUrl,
                    resourceObjects,
                    swaggerResourcePath,
                    documentVersion)
                : null;
      } else {
        return false;
      }

    } else if (SwaggerConstants.SWAGGER_VERSION_2.equals(swaggerVersion)) {
      if (addSwaggerDocumentToRegistry(
          swaggerContentStream, swaggerResourcePath, documentVersion)) {
        createEndpointElement(swaggerDocObject, swaggerVersion);
        restServiceElement =
            RESTServiceUtils.createRestServiceArtifact(
                swaggerDocObject,
                swaggerVersion,
                endpointUrl,
                null,
                swaggerResourcePath,
                documentVersion);
      } else {
        return false;
      }
    }

    /*
    If REST Service content is not empty, saves the REST service and adds the relevant associations.
     */
    if (restServiceElement != null) {
      String servicePath =
          RESTServiceUtils.addServiceToRegistry(requestContext, restServiceElement);
      registry.addAssociation(servicePath, swaggerResourcePath, CommonConstants.DEPENDS);
      registry.addAssociation(swaggerResourcePath, servicePath, CommonConstants.USED_BY);

      if (endpointUrl != null) {
        String endpointPath =
            RESTServiceUtils.addEndpointToRegistry(
                requestContext, endpointElement, endpointLocation);
        registry.addAssociation(servicePath, endpointPath, CommonConstants.DEPENDS);
        registry.addAssociation(endpointPath, servicePath, CommonConstants.USED_BY);
      }
    } else {
      log.warn("Service content is null. Cannot create the REST Service artifact.");
    }

    CommonUtil.closeOutputStream(swaggerContentStream);

    return true;
  }