Skip to content

Commit 145ec27

Browse files
committed
Fix the problem with the generation of Json payloads.
1 parent dcfc4e2 commit 145ec27

File tree

12 files changed

+247
-102
lines changed

12 files changed

+247
-102
lines changed

core/esmf-aspect-meta-model-java/src/main/java/org/eclipse/esmf/metamodel/ComplexType.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,10 @@ default List<ComplexType> getExtendingElements() {
3232
return Collections.emptyList();
3333
}
3434

35+
default List<ComplexType> getExtendingElements( final ExtendedAspectContext context ) {
36+
return Collections.emptyList();
37+
}
38+
3539
default boolean isAbstractEntity() {
3640
return false;
3741
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
/*
2+
* Copyright (c) 2023 Robert Bosch Manufacturing Solutions GmbH
3+
*
4+
* See the AUTHORS file(s) distributed with this work for additional
5+
* information regarding authorship.
6+
*
7+
* This Source Code Form is subject to the terms of the Mozilla Public
8+
* License, v. 2.0. If a copy of the MPL was not distributed with this
9+
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
10+
*
11+
* SPDX-License-Identifier: MPL-2.0
12+
*/
13+
14+
package org.eclipse.esmf.metamodel;
15+
16+
import java.util.Map;
17+
18+
import org.eclipse.esmf.aspectmodel.resolver.services.VersionedModel;
19+
import org.eclipse.esmf.aspectmodel.urn.AspectModelUrn;
20+
21+
/**
22+
* The ExtendedAspectContext wraps a loaded/resolved Aspect Model, a single Aspect that was instantiated from this model, i.e.,
23+
* which must be defined in the RDF model, and a list of all elements that were instantiated in the context of the given model.
24+
* @param rdfModel the RDF model
25+
* @param aspect the Aspect
26+
* @param loadedElements all elements instantiated in the context of the given model
27+
*/
28+
public record ExtendedAspectContext(VersionedModel rdfModel, Aspect aspect, Map<AspectModelUrn, ModelElement> loadedElements) {
29+
}

core/esmf-aspect-meta-model-java/src/main/java/org/eclipse/esmf/metamodel/impl/DefaultComplexType.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import org.eclipse.esmf.aspectmodel.urn.AspectModelUrn;
2626
import org.eclipse.esmf.metamodel.Aspect;
2727
import org.eclipse.esmf.metamodel.ComplexType;
28+
import org.eclipse.esmf.metamodel.ExtendedAspectContext;
2829
import org.eclipse.esmf.metamodel.Property;
2930
import org.eclipse.esmf.metamodel.loader.MetaModelBaseAttributes;
3031
import org.eclipse.esmf.metamodel.visitor.AspectVisitor;
@@ -73,11 +74,21 @@ public Optional<ComplexType> getExtends() {
7374
* @return all {@link ComplexType} instances from the {@link DefaultComplexType#instances} Map which extend this
7475
* Abstract Entity.
7576
*/
77+
@Deprecated( forRemoval = true )
7678
@Override
7779
public List<ComplexType> getExtendingElements() {
7880
return extendingElements.stream().map( instances::get ).filter( Objects::nonNull ).collect( Collectors.toList() );
7981
}
8082

83+
@Override
84+
public List<ComplexType> getExtendingElements( final ExtendedAspectContext context ) {
85+
return extendingElements.stream()
86+
.map( urn -> context.loadedElements().get( urn ) )
87+
.filter( Objects::nonNull )
88+
.map( modelElement -> (ComplexType) modelElement )
89+
.collect( Collectors.toList() );
90+
}
91+
8192
public static Map<AspectModelUrn, ComplexType> getInstances() {
8293
return Collections.unmodifiableMap( instances );
8394
}

core/esmf-aspect-meta-model-java/src/main/java/org/eclipse/esmf/metamodel/loader/AspectModelLoader.java

Lines changed: 70 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import java.util.Map;
2020
import java.util.Optional;
2121
import java.util.Set;
22+
import java.util.function.Function;
2223
import java.util.function.Predicate;
2324
import java.util.stream.Collectors;
2425

@@ -27,29 +28,29 @@
2728
import org.apache.jena.rdf.model.Resource;
2829
import org.apache.jena.rdf.model.Statement;
2930
import org.apache.jena.vocabulary.RDF;
31+
import org.eclipse.esmf.aspectmodel.UnsupportedVersionException;
32+
import org.eclipse.esmf.aspectmodel.resolver.AspectModelResolver;
3033
import org.eclipse.esmf.aspectmodel.resolver.FileSystemStrategy;
34+
import org.eclipse.esmf.aspectmodel.resolver.exceptions.InvalidModelException;
35+
import org.eclipse.esmf.aspectmodel.resolver.exceptions.InvalidNamespaceException;
36+
import org.eclipse.esmf.aspectmodel.resolver.exceptions.InvalidRootElementCountException;
37+
import org.eclipse.esmf.aspectmodel.resolver.services.VersionedModel;
38+
import org.eclipse.esmf.aspectmodel.urn.AspectModelUrn;
39+
import org.eclipse.esmf.aspectmodel.versionupdate.MigratorService;
3140
import org.eclipse.esmf.aspectmodel.vocabulary.SAMM;
3241
import org.eclipse.esmf.metamodel.Aspect;
3342
import org.eclipse.esmf.metamodel.AspectContext;
43+
import org.eclipse.esmf.metamodel.ExtendedAspectContext;
3444
import org.eclipse.esmf.metamodel.ModelElement;
3545
import org.eclipse.esmf.metamodel.ModelNamespace;
3646
import org.eclipse.esmf.metamodel.NamedElement;
3747
import org.eclipse.esmf.metamodel.impl.DefaultModelNamespace;
48+
import org.eclipse.esmf.samm.KnownVersion;
3849
import org.slf4j.Logger;
3950
import org.slf4j.LoggerFactory;
4051

4152
import com.google.common.collect.ImmutableSet;
4253

43-
import org.eclipse.esmf.samm.KnownVersion;
44-
import org.eclipse.esmf.aspectmodel.UnsupportedVersionException;
45-
import org.eclipse.esmf.aspectmodel.resolver.AspectModelResolver;
46-
import org.eclipse.esmf.aspectmodel.resolver.exceptions.InvalidModelException;
47-
import org.eclipse.esmf.aspectmodel.resolver.exceptions.InvalidNamespaceException;
48-
import org.eclipse.esmf.aspectmodel.resolver.exceptions.InvalidRootElementCountException;
49-
import org.eclipse.esmf.aspectmodel.resolver.exceptions.InvalidVersionException;
50-
import org.eclipse.esmf.aspectmodel.resolver.services.VersionedModel;
51-
import org.eclipse.esmf.aspectmodel.versionupdate.MigratorService;
52-
5354
import io.vavr.control.Try;
5455

5556
/**
@@ -202,6 +203,19 @@ public static Try<Aspect> getSingleAspect( final VersionedModel versionedModel )
202203
return getSingleAspect( versionedModel, aspect -> true );
203204
}
204205

206+
/**
207+
* Convenience method to load the single Aspect + it's extended context from a model, when the model contains exactly one Aspect.
208+
*
209+
* <b>Caution:</b> The method handles this special case. Aspect Models are allowed to contain any number of Aspects (including zero),
210+
* so for the general case you should use {@link #getElements(VersionedModel)} instead.
211+
*
212+
* @param versionedModel The RDF model representation of the Aspect model
213+
* @return the single Aspect contained in the model together with it's extended context
214+
*/
215+
public static Try<ExtendedAspectContext> getSingleAspectWithContext( final VersionedModel versionedModel ) {
216+
return getSingleAspectWithContext( versionedModel, aspect -> true );
217+
}
218+
205219
/**
206220
* Convenience method to load the single Aspect from a model, when the model contains exactly one Aspect. Does the same as
207221
* {@link #getSingleAspect(VersionedModel)} but throws an exception on failure.
@@ -219,6 +233,23 @@ public static Aspect getSingleAspectUnchecked( final VersionedModel versionedMod
219233
} );
220234
}
221235

236+
/**
237+
* Convenience method to load the single Aspect from a model, when the model contains exactly one Aspect. Does the same as
238+
* {@link #getSingleAspectWithContext(VersionedModel)} but throws an exception on failure.
239+
*
240+
* <b>Caution:</b> The method handles this special case. Aspect Models are allowed to contain any number of Aspects (including zero),
241+
* so for the general case you should use {@link #getElementsUnchecked(VersionedModel)} instead.
242+
*
243+
* @param versionedModel The RDF model representation of the Aspect model
244+
* @return the single Aspect contained in the model plus it's extended context (elements loaded in the context of this model)
245+
*/
246+
public static ExtendedAspectContext getSingleAspectUncheckedWithContext( final VersionedModel versionedModel ) {
247+
return getSingleAspectWithContext( versionedModel ).getOrElseThrow( cause -> {
248+
LOG.error( "Could not load aspect", cause );
249+
throw new AspectLoadingException( cause );
250+
} );
251+
}
252+
222253
/**
223254
* Similar to {@link #getSingleAspect(VersionedModel)}, except that a predicate can be provided to select which of potentially
224255
* multiple aspects should be selected
@@ -228,7 +259,7 @@ public static Aspect getSingleAspectUnchecked( final VersionedModel versionedMod
228259
*/
229260
public static Try<Aspect> getSingleAspect( final VersionedModel versionedModel, final Predicate<Aspect> selector ) {
230261
return getAspects( versionedModel ).flatMap( allAspects -> {
231-
final List<Aspect> aspects = allAspects.stream().filter( selector::test ).toList();
262+
final List<Aspect> aspects = allAspects.stream().filter( selector ).toList();
232263
return switch ( aspects.size() ) {
233264
case 1 -> Try.success( aspects.iterator().next() );
234265
case 0 -> Try.failure( new InvalidRootElementCountException( "No Aspects were found in the model" ) );
@@ -254,4 +285,32 @@ public static Try<AspectContext> getAspectContext( final File input ) {
254285
getSingleAspect( versionedModel, aspect -> aspect.getName().equals( input.getName() ) )
255286
.map( aspect -> new AspectContext( versionedModel, aspect ) ) );
256287
}
288+
289+
/**
290+
* Similar to {@link #getSingleAspectWithContext(VersionedModel)}, except that a predicate can be provided to select which of potentially
291+
* multiple aspects should be selected
292+
* @param versionedModel the RDF model reprensentation of the Aspect model
293+
* @param selector the predicate to select an Aspect
294+
* @return the extended context, or a failure if 0 or more than 1 matching Aspects were found
295+
*/
296+
public static Try<ExtendedAspectContext> getSingleAspectWithContext( final VersionedModel versionedModel, final Predicate<Aspect> selector ) {
297+
final Try<List<ModelElement>> allElements = getElements( versionedModel );
298+
final List<Aspect> aspects = allElements.map( elements -> elements.stream().filter( element -> element.is( Aspect.class ) )
299+
.map( element -> element.as( Aspect.class ) )
300+
.filter( selector )
301+
.toList() ).get();
302+
return switch ( aspects.size() ) {
303+
case 1 -> Try.success( new ExtendedAspectContext( versionedModel, aspects.iterator().next(), getLoadedElementMap( allElements.get() ) ) );
304+
case 0 -> Try.failure( new InvalidRootElementCountException( "No Aspects were found in the model" ) );
305+
default -> Try.failure( new AspectLoadingException( "Multiple Aspects were found in the resolved model" ) );
306+
};
307+
}
308+
309+
private static Map<AspectModelUrn, ModelElement> getLoadedElementMap( final List<ModelElement> loadedElements ) {
310+
return loadedElements.stream()
311+
.filter( element -> element.is( NamedElement.class ) )
312+
.map( element -> element.as( NamedElement.class ) )
313+
.filter( element -> element.getAspectModelUrn().isPresent() )
314+
.collect( Collectors.toMap( element -> element.getAspectModelUrn().get(), Function.identity() ) );
315+
}
257316
}

core/esmf-aspect-model-document-generators/src/main/java/org/eclipse/esmf/aspectmodel/generator/json/AspectModelJsonPayloadGenerator.java

Lines changed: 21 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -46,17 +46,6 @@
4646
import org.apache.jena.vocabulary.XSD;
4747
import org.eclipse.esmf.aspectmodel.generator.AbstractGenerator;
4848
import org.eclipse.esmf.aspectmodel.generator.NumericTypeTraits;
49-
import org.eclipse.esmf.aspectmodel.vocabulary.SAMM;
50-
import org.jeasy.random.EasyRandom;
51-
import org.jeasy.random.EasyRandomParameters;
52-
53-
import com.fasterxml.jackson.databind.ObjectMapper;
54-
import com.fasterxml.jackson.databind.SerializationFeature;
55-
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
56-
import com.github.curiousoddman.rgxgen.RgxGen;
57-
import com.google.common.collect.ImmutableList;
58-
import com.google.common.collect.ImmutableMap;
59-
6049
import org.eclipse.esmf.aspectmodel.jackson.AspectModelJacksonModule;
6150
import org.eclipse.esmf.aspectmodel.resolver.services.DataType;
6251
import org.eclipse.esmf.characteristic.Collection;
@@ -68,19 +57,27 @@
6857
import org.eclipse.esmf.constraint.RangeConstraint;
6958
import org.eclipse.esmf.constraint.RegularExpressionConstraint;
7059
import org.eclipse.esmf.metamodel.AbstractEntity;
71-
import org.eclipse.esmf.metamodel.Aspect;
72-
import org.eclipse.esmf.metamodel.AspectContext;
7360
import org.eclipse.esmf.metamodel.Characteristic;
7461
import org.eclipse.esmf.metamodel.ComplexType;
7562
import org.eclipse.esmf.metamodel.Constraint;
7663
import org.eclipse.esmf.metamodel.Entity;
64+
import org.eclipse.esmf.metamodel.ExtendedAspectContext;
7765
import org.eclipse.esmf.metamodel.Property;
7866
import org.eclipse.esmf.metamodel.Scalar;
7967
import org.eclipse.esmf.metamodel.ScalarValue;
8068
import org.eclipse.esmf.metamodel.Type;
8169
import org.eclipse.esmf.metamodel.Value;
8270
import org.eclipse.esmf.metamodel.datatypes.Curie;
8371
import org.eclipse.esmf.metamodel.impl.BoundDefinition;
72+
import org.jeasy.random.EasyRandom;
73+
import org.jeasy.random.EasyRandomParameters;
74+
75+
import com.fasterxml.jackson.databind.ObjectMapper;
76+
import com.fasterxml.jackson.databind.SerializationFeature;
77+
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
78+
import com.github.curiousoddman.rgxgen.RgxGen;
79+
import com.google.common.collect.ImmutableList;
80+
import com.google.common.collect.ImmutableMap;
8481

8582
public class AspectModelJsonPayloadGenerator extends AbstractGenerator {
8683
/**
@@ -90,27 +87,20 @@ public class AspectModelJsonPayloadGenerator extends AbstractGenerator {
9087
private static final String EITHER_LEFT = "left";
9188
private static final double THRESHOLD = .0001;
9289

93-
private final Aspect aspect;
9490
private final List<Transformer> transformers;
9591
private final ExampleValueGenerator exampleValueGenerator;
9692
private final ObjectMapper objectMapper;
9793
private final List<Property> recursiveProperty;
9894
private final ValueToPayloadStructure valueToPayloadStructure = new ValueToPayloadStructure();
9995

100-
public AspectModelJsonPayloadGenerator( final Aspect aspect ) {
101-
this( aspect, new SAMM( aspect.getMetaModelVersion() ), new Random() );
102-
}
103-
104-
public AspectModelJsonPayloadGenerator( final AspectContext context ) {
105-
this( context.aspect() );
106-
}
107-
108-
public AspectModelJsonPayloadGenerator( final Aspect aspect, final Random randomStrategy ) {
109-
this( aspect, new SAMM( aspect.getMetaModelVersion() ), randomStrategy );
96+
private final ExtendedAspectContext context;
97+
98+
public AspectModelJsonPayloadGenerator( final ExtendedAspectContext context ) {
99+
this( context, new Random() );
110100
}
111101

112-
private AspectModelJsonPayloadGenerator( final Aspect aspect, final SAMM samm, final Random randomStrategy ) {
113-
this.aspect = aspect;
102+
public AspectModelJsonPayloadGenerator( final ExtendedAspectContext context, final Random randomStrategy ) {
103+
this.context = context;
114104
exampleValueGenerator = new ExampleValueGenerator( randomStrategy );
115105
objectMapper = AspectModelJsonPayloadGenerator.createObjectMapper();
116106
objectMapper.configure( SerializationFeature.FAIL_ON_EMPTY_BEANS, false );
@@ -129,7 +119,7 @@ private AspectModelJsonPayloadGenerator( final Aspect aspect, final SAMM samm, f
129119
* @param nameMapper The callback function that maps the Aspect name to an OutputStream
130120
*/
131121
public void generateJson( final Function<String, OutputStream> nameMapper ) throws IOException {
132-
try ( final OutputStream output = nameMapper.apply( aspect.getName() ) ) {
122+
try ( final OutputStream output = nameMapper.apply( context.aspect().getName() ) ) {
133123
output.write( generateJson().getBytes() );
134124
}
135125
}
@@ -140,7 +130,7 @@ public void generateJson( final Function<String, OutputStream> nameMapper ) thro
140130
* @see #generateJson(Function)
141131
*/
142132
public void generateJsonPretty( final Function<String, OutputStream> nameMapper ) throws IOException {
143-
try ( final OutputStream output = nameMapper.apply( aspect.getName() ) ) {
133+
try ( final OutputStream output = nameMapper.apply( context.aspect().getName() ) ) {
144134
output.write( generateJsonPretty().getBytes() );
145135
}
146136
}
@@ -162,7 +152,7 @@ private static ObjectMapper createObjectMapper() {
162152
}
163153

164154
private Map<String, Object> transformAspectProperties() {
165-
return transformProperties( aspect.getProperties() );
155+
return transformProperties( context.aspect().getProperties() );
166156
}
167157

168158
/**
@@ -228,7 +218,7 @@ private Map<String, Object> transformAbstractEntityProperty( final BasicProperty
228218
final Optional<AbstractEntity> dataType = getForCharacteristic( property.getCharacteristic(), AbstractEntity.class );
229219
if ( dataType.isPresent() ) {
230220
final AbstractEntity abstractEntity = dataType.get();
231-
final ComplexType extendingComplexType = abstractEntity.getExtendingElements().get( 0 );
221+
final ComplexType extendingComplexType = abstractEntity.getExtendingElements( context ).get( 0 );
232222
final Map<String, Object> generatedProperties = transformProperties( extendingComplexType.getAllProperties() );
233223
generatedProperties.put( "@type", extendingComplexType.getName() );
234224
return toMap( property.getName(), generatedProperties );
@@ -304,7 +294,7 @@ private List<Object> getCollectionValues( final BasicProperty property, final Co
304294
final Type dataType = collection.getDataType().orElseThrow( () -> new IllegalArgumentException( "DataType for collection is required." ) );
305295
if ( dataType.is( AbstractEntity.class ) ) {
306296
final AbstractEntity abstractEntity = dataType.as( AbstractEntity.class );
307-
final ComplexType extendingComplexType = abstractEntity.getExtendingElements().get( 0 );
297+
final ComplexType extendingComplexType = abstractEntity.getExtendingElements( context ).get( 0 );
308298
final Map<String, Object> propertyValueMap = transformProperties( extendingComplexType.getAllProperties() );
309299
propertyValueMap.put( "@type", extendingComplexType.getName() );
310300
return ImmutableList.of( propertyValueMap );

0 commit comments

Comments
 (0)