All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.openmanufacturing.sds.aspectmodel.GenerateOpenApiSpec Maven / Gradle / Ivy

/*
 * Copyright (c) 2022 Robert Bosch Manufacturing Solutions GmbH
 *
 * See the AUTHORS file(s) distributed with this work for additional
 * information regarding authorship.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/.
 *
 * SPDX-License-Identifier: MPL-2.0
 */

package io.openmanufacturing.sds.aspectmodel;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
import java.util.Optional;
import java.util.Set;

import org.apache.commons.io.IOUtils;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugins.annotations.LifecyclePhase;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.JsonNodeFactory;

import io.openmanufacturing.sds.aspectmodel.generator.openapi.AspectModelOpenApiGenerator;
import io.openmanufacturing.sds.aspectmodel.generator.openapi.PagingOption;
import io.openmanufacturing.sds.aspectmodel.resolver.services.VersionedModel;
import io.openmanufacturing.sds.metamodel.Aspect;
import io.openmanufacturing.sds.metamodel.loader.AspectModelLoader;

@Mojo( name = "generateOpenApiSpec", defaultPhase =  LifecyclePhase.GENERATE_RESOURCES )
public class GenerateOpenApiSpec extends AspectModelMojo {

   private final Logger logger = LoggerFactory.getLogger( GenerateOpenApiSpec.class );

   private final AspectModelOpenApiGenerator generator = new AspectModelOpenApiGenerator();
   private final ObjectMapper objectMapper = new ObjectMapper();

   @Parameter( required = true )
   private String aspectApiBaseUrl = "";

   @Parameter
   private String aspectParameterFile;

   @Parameter( defaultValue = "false" )
   private boolean useSemanticApiVersion;

   @Parameter
   private String aspectResourcePath;

   @Parameter( defaultValue = "false" )
   private boolean includeQueryApi;

   @Parameter( defaultValue = "false" )
   private boolean excludePaging;

   @Parameter( defaultValue = "false" )
   private boolean aspectCursorBasedPaging;

   @Parameter( defaultValue = "false" )
   private boolean aspectOffsetBasedPaging;

   @Parameter( defaultValue = "false" )
   private boolean aspectTimeBasedPaging;

   @Parameter( required = true )
   private String outputFormat = "";

   @Override
   public void execute() throws MojoExecutionException, MojoFailureException {
      validateParameters();

      final Set aspectModels = loadModelsOrFail();
      try {
         final OpenApiFormat format = OpenApiFormat.valueOf( outputFormat.toUpperCase() );
         if ( format.equals( OpenApiFormat.JSON ) ) {
            generateOpenApiSpecJson( aspectModels );
            return;
         }
         generateOpenApiSpecYaml( aspectModels );
         logger.info( "Successfully generated OpenAPI specification for Aspect Models." );
      } catch ( final IllegalArgumentException exception ) {
         throw new MojoExecutionException( "Invalid output format.", exception );
      }
   }

   @Override
   protected void validateParameters() throws MojoExecutionException {
      if ( aspectApiBaseUrl.isEmpty() ) {
         throw new MojoExecutionException( "Missing configuration. Please provide the Aspect API base URL." );
      }
      if ( outputFormat.isEmpty() ) {
         throw new MojoExecutionException( "Missing configuration. Please provide an output format." );
      }
      super.validateParameters();
   }

   private void generateOpenApiSpecJson( final Set aspectModels ) throws MojoExecutionException {
      for ( final VersionedModel aspectModel : aspectModels ) {
         final Aspect aspect = AspectModelLoader.fromVersionedModelUnchecked( aspectModel );
         JsonNode result = JsonNodeFactory.instance.objectNode();
         final Optional aspectParameterDefinitionFile = getFileAsString( aspectParameterFile );
         if ( aspectParameterDefinitionFile.isPresent() ) {
            try {
               result = objectMapper.readTree( aspectParameterDefinitionFile.get() );
            } catch ( final JsonProcessingException e ) {
               throw new MojoExecutionException( "Could not parse the file to JSON.", e );
            }
         }
         final JsonNode jsonSpec = generator.applyForJson( aspect, useSemanticApiVersion, aspectApiBaseUrl, Optional.ofNullable( aspectResourcePath ),
               Optional.of( result ), includeQueryApi, getPagingFromArgs() );

         final OutputStream out = getStreamForFile( aspect.getName() + ".oai.json", outputDirectory );
         try {
            objectMapper.writerWithDefaultPrettyPrinter().writeValue( out, jsonSpec );
            out.flush();
         } catch ( final IOException exception ) {
            throw new MojoExecutionException( "Could not format OpenAPI JSON.", exception );
         }
      }
   }

   private void generateOpenApiSpecYaml( final Set aspectModels ) throws MojoExecutionException {
      for ( final VersionedModel aspectModel : aspectModels ) {
         final Aspect aspect = AspectModelLoader.fromVersionedModelUnchecked( aspectModel );
         try {
            final String yamlSpec = generator.applyForYaml( aspect, useSemanticApiVersion, aspectApiBaseUrl, Optional.ofNullable( aspectResourcePath ),
                  getFileAsString( aspectParameterFile ), includeQueryApi, getPagingFromArgs() );
            final OutputStream out = getStreamForFile( aspect.getName() + ".oai.yaml", outputDirectory );
            out.write( yamlSpec.getBytes() );
            out.flush();
            out.close();
         } catch ( final IOException exception ) {
            throw new MojoExecutionException( "Could not generate OpenAPI YAML specification.", exception );
         }
      }
   }

   private static Optional getFileAsString( final String filePath ) throws MojoExecutionException {
      if ( filePath == null || filePath.isEmpty() ) {
         return Optional.empty();
      }
      final File f = new File( filePath );
      if ( f.exists() && !f.isDirectory() ) {
         try {
            final InputStream inputStream = new FileInputStream( filePath );
            return Optional.of( IOUtils.toString( inputStream, StandardCharsets.UTF_8.name() ) );
         } catch ( final IOException e ) {
            final String errorMessage = String.format( "Could not load file %s.", filePath );
            throw new MojoExecutionException( errorMessage, e );
         }
      }
      final String errorMessage = String.format( "File does not exist %s.", filePath );
      throw new MojoExecutionException( errorMessage );
   }

   private Optional getPagingFromArgs() {
      if ( excludePaging ) {
         return Optional.of( PagingOption.NO_PAGING );
      }
      if ( aspectCursorBasedPaging ) {
         return Optional.of( PagingOption.CURSOR_BASED_PAGING );
      }
      if ( aspectOffsetBasedPaging ) {
         return Optional.of( PagingOption.OFFSET_BASED_PAGING );
      }
      if ( aspectTimeBasedPaging ) {
         return Optional.of( PagingOption.TIME_BASED_PAGING );
      }
      return Optional.empty();
   }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy