1616import java .io .ByteArrayOutputStream ;
1717import java .io .IOException ;
1818import java .nio .charset .StandardCharsets ;
19+ import java .nio .file .Path ;
20+ import java .util .HashMap ;
1921import java .util .Locale ;
22+ import java .util .Map ;
2023import java .util .Optional ;
2124
2225import org .apache .commons .lang3 .LocaleUtils ;
26+ import org .eclipse .esmf .ame .exceptions .FileHandlingException ;
2327import org .eclipse .esmf .ame .exceptions .GenerationException ;
2428import org .eclipse .esmf .ame .exceptions .InvalidAspectModelException ;
2529import org .eclipse .esmf .ame .resolver .strategy .FileSystemStrategy ;
2630import org .eclipse .esmf .ame .resolver .strategy .utils .ResolverUtils ;
31+ import org .eclipse .esmf .ame .services .utils .ZipUtils ;
2732import org .eclipse .esmf .ame .utils .ModelUtils ;
2833import org .eclipse .esmf .aspectmodel .aas .AasFileFormat ;
2934import org .eclipse .esmf .aspectmodel .aas .AspectModelAasGenerator ;
35+ import org .eclipse .esmf .aspectmodel .generator .asyncapi .AspectModelAsyncApiGenerator ;
36+ import org .eclipse .esmf .aspectmodel .generator .asyncapi .AsyncApiSchemaArtifact ;
37+ import org .eclipse .esmf .aspectmodel .generator .asyncapi .AsyncApiSchemaGenerationConfig ;
38+ import org .eclipse .esmf .aspectmodel .generator .asyncapi .AsyncApiSchemaGenerationConfigBuilder ;
3039import org .eclipse .esmf .aspectmodel .generator .docu .AspectModelDocumentationGenerator ;
3140import org .eclipse .esmf .aspectmodel .generator .json .AspectModelJsonPayloadGenerator ;
3241import org .eclipse .esmf .aspectmodel .generator .jsonschema .AspectModelJsonSchemaGenerator ;
3342import org .eclipse .esmf .aspectmodel .generator .openapi .AspectModelOpenApiGenerator ;
3443import org .eclipse .esmf .aspectmodel .generator .openapi .PagingOption ;
3544import org .eclipse .esmf .aspectmodel .resolver .services .DataType ;
3645import org .eclipse .esmf .aspectmodel .resolver .services .VersionedModel ;
46+ import org .eclipse .esmf .metamodel .Aspect ;
3747import org .eclipse .esmf .metamodel .AspectContext ;
3848import org .slf4j .Logger ;
3949import org .slf4j .LoggerFactory ;
4050import org .springframework .stereotype .Service ;
4151
52+ import com .fasterxml .jackson .core .JsonProcessingException ;
4253import com .fasterxml .jackson .databind .JsonNode ;
4354import com .fasterxml .jackson .databind .ObjectMapper ;
55+ import com .fasterxml .jackson .dataformat .yaml .YAMLGenerator ;
56+ import com .fasterxml .jackson .dataformat .yaml .YAMLMapper ;
4457import com .google .common .collect .ImmutableMap ;
4558
4659import io .vavr .control .Try ;
4760
4861@ Service
4962public class GenerateService {
5063 private static final Logger LOG = LoggerFactory .getLogger ( GenerateService .class );
51-
64+ private static final ObjectMapper YAML_MAPPER = new YAMLMapper (). enable ( YAMLGenerator . Feature . MINIMIZE_QUOTES );
5265 private static final String COULD_NOT_LOAD_ASPECT = "Could not load Aspect" ;
5366 private static final String COULD_NOT_LOAD_ASPECT_MODEL = "Could not load Aspect model, please make sure the model is valid." ;
5467 public static final String WRONG_RESOURCE_PATH_ID = "The resource path ID and properties ID do not match. Please verify and correct them." ;
@@ -90,8 +103,7 @@ public String jsonSchema( final String aspectModel, final String language ) {
90103
91104 public String sampleJSONPayload ( final String aspectModel ) {
92105 try {
93- return new AspectModelJsonPayloadGenerator (
94- generateAspectContext ( aspectModel ) ).generateJson ();
106+ return new AspectModelJsonPayloadGenerator ( generateAspectContext ( aspectModel ) ).generateJson ();
95107 } catch ( final IOException e ) {
96108 LOG .error ( COULD_NOT_LOAD_ASPECT_MODEL );
97109 throw new InvalidAspectModelException ( COULD_NOT_LOAD_ASPECT , e );
@@ -144,30 +156,24 @@ private AspectContext generateAspectContext( final String aspectModel ) {
144156 public String generateYamlOpenApiSpec ( final String language , final String aspectModel , final String baseUrl ,
145157 final boolean includeQueryApi , final boolean useSemanticVersion , final Optional <PagingOption > pagingOption ,
146158 final Optional <String > resourcePath , final Optional <String > yamlProperties ) {
147- try {
148- final String ymlOutput = new AspectModelOpenApiGenerator ().applyForYaml (
149- ResolverUtils .resolveAspectFromModel ( aspectModel ),
150- useSemanticVersion , baseUrl , resourcePath , yamlProperties , includeQueryApi , pagingOption ,
151- Locale .forLanguageTag ( language ) );
152-
153- if ( ymlOutput .equals ( "--- {}\n " ) ) {
154- throw new GenerationException ( WRONG_RESOURCE_PATH_ID );
155- }
159+ final String ymlOutput = new AspectModelOpenApiGenerator ().applyForYaml (
160+ ResolverUtils .resolveAspectFromModel ( aspectModel ), useSemanticVersion , baseUrl , resourcePath ,
161+ yamlProperties , includeQueryApi , pagingOption , Locale .forLanguageTag ( language ) );
156162
157- return ymlOutput ;
158- } catch ( final IOException e ) {
159- LOG .error ( "YAML OpenAPI specification could not be generated." );
160- throw new InvalidAspectModelException ( "Error generating YAML OpenAPI specification" , e );
163+ if ( ymlOutput .equals ( "--- {}\n " ) ) {
164+ throw new GenerationException ( WRONG_RESOURCE_PATH_ID );
161165 }
166+
167+ return ymlOutput ;
162168 }
163169
164170 public String generateJsonOpenApiSpec ( final String language , final String aspectModel , final String baseUrl ,
165171 final boolean includeQueryApi , final boolean useSemanticVersion , final Optional <PagingOption > pagingOption ,
166172 final Optional <String > resourcePath , final Optional <JsonNode > jsonProperties ) {
167173 try {
168174 final JsonNode json = new AspectModelOpenApiGenerator ().applyForJson (
169- ResolverUtils .resolveAspectFromModel ( aspectModel ), useSemanticVersion , baseUrl ,
170- resourcePath , jsonProperties , includeQueryApi , pagingOption , LocaleUtils .toLocale ( language ) );
175+ ResolverUtils .resolveAspectFromModel ( aspectModel ), useSemanticVersion , baseUrl , resourcePath ,
176+ jsonProperties , includeQueryApi , pagingOption , LocaleUtils .toLocale ( language ) );
171177
172178 final ByteArrayOutputStream out = new ByteArrayOutputStream ();
173179 final ObjectMapper objectMapper = new ObjectMapper ();
@@ -186,4 +192,83 @@ public String generateJsonOpenApiSpec( final String language, final String aspec
186192 throw new InvalidAspectModelException ( "Error generating JSON OpenAPI specification" , e );
187193 }
188194 }
195+
196+ public byte [] generateAsyncApiSpec ( final String aspectModel , final String language , final String output ,
197+ final String applicationId , final String channelAddress , final boolean useSemanticVersion ,
198+ final boolean writeSeparateFiles ) {
199+ final AspectModelAsyncApiGenerator generator = new AspectModelAsyncApiGenerator ();
200+ final AsyncApiSchemaGenerationConfig config = buildAsyncApiSchemaGenerationConfig ( applicationId , channelAddress ,
201+ useSemanticVersion , language );
202+
203+ final Aspect aspect = ResolverUtils .resolveAspectFromModel ( aspectModel );
204+ final AsyncApiSchemaArtifact asyncApiSpec = generator .apply ( aspect , config );
205+
206+ if ( writeSeparateFiles ) {
207+ return generateZipFile ( asyncApiSpec , output );
208+ }
209+
210+ return generateSingleFile ( asyncApiSpec , output );
211+ }
212+
213+ private AsyncApiSchemaGenerationConfig buildAsyncApiSchemaGenerationConfig ( final String applicationId ,
214+ final String channelAddress , final boolean useSemanticVersion , final String language ) {
215+ return AsyncApiSchemaGenerationConfigBuilder .builder ().useSemanticVersion ( useSemanticVersion )
216+ .applicationId ( applicationId ).channelAddress ( channelAddress )
217+ .locale ( LocaleUtils .toLocale ( language ) ).build ();
218+ }
219+
220+ private byte [] generateZipFile ( final AsyncApiSchemaArtifact asyncApiSpec , final String output ) {
221+ if ( output .equals ( "json" ) ) {
222+ return jsonZip ( asyncApiSpec .getContentWithSeparateSchemasAsJson () );
223+ }
224+
225+ return yamlZip ( asyncApiSpec .getContentWithSeparateSchemasAsYaml () );
226+ }
227+
228+ private byte [] jsonZip ( final Map <Path , JsonNode > separateFilesContent ) {
229+ final ObjectMapper objectMapper = new ObjectMapper ();
230+ final Map <Path , byte []> content = new HashMap <>();
231+
232+ for ( final Map .Entry <Path , JsonNode > entry : separateFilesContent .entrySet () ) {
233+ try {
234+ final byte [] bytes = objectMapper .writerWithDefaultPrettyPrinter ().writeValueAsBytes ( entry .getValue () );
235+ content .put ( entry .getKey (), bytes );
236+ } catch ( final JsonProcessingException e ) {
237+ LOG .error ( "Failed to convert JSON to bytes." , e );
238+ throw new FileHandlingException ( "Failed to get JSON async api." , e );
239+ }
240+ }
241+
242+ return ZipUtils .createAsyncApiPackage ( content );
243+ }
244+
245+ private byte [] yamlZip ( final Map <Path , String > separateFilesContent ) {
246+ final Map <Path , byte []> content = new HashMap <>();
247+
248+ for ( final Map .Entry <Path , String > entry : separateFilesContent .entrySet () ) {
249+ final byte [] bytes = entry .getValue ().getBytes ( StandardCharsets .UTF_8 );
250+ content .put ( entry .getKey (), bytes );
251+ }
252+
253+ return ZipUtils .createAsyncApiPackage ( content );
254+ }
255+
256+ private byte [] generateSingleFile ( final AsyncApiSchemaArtifact asyncApiSpec , final String output ) {
257+ final JsonNode json = asyncApiSpec .getContent ();
258+
259+ if ( output .equals ( "yaml" ) ) {
260+ return jsonToYaml ( json ).getBytes ( StandardCharsets .UTF_8 );
261+ }
262+
263+ return json .toString ().getBytes ( StandardCharsets .UTF_8 );
264+ }
265+
266+ private String jsonToYaml ( final JsonNode json ) {
267+ try {
268+ return YAML_MAPPER .writeValueAsString ( json );
269+ } catch ( final JsonProcessingException e ) {
270+ LOG .error ( "JSON could not be converted to YAML" , e );
271+ throw new FileHandlingException ( "Failed to get YAML async api." , e );
272+ }
273+ }
189274}
0 commit comments