1515
1616import java .io .File ;
1717import java .net .URI ;
18- import java .nio .file .Path ;
19- import java .nio .file .Paths ;
2018import java .util .Comparator ;
19+ import java .util .LinkedHashMap ;
2120import java .util .List ;
2221import java .util .Map ;
23- import java .util .TreeMap ;
24- import java .util .regex .Pattern ;
2522import java .util .stream .Collectors ;
2623import java .util .stream .Stream ;
2724
2825import org .eclipse .esmf .ame .services .models .Model ;
2926import org .eclipse .esmf .ame .services .models .Version ;
3027import org .eclipse .esmf .aspectmodel .loader .AspectModelLoader ;
31- import org .eclipse .esmf .metamodel .AspectModel ;
3228import org .eclipse .esmf .metamodel .ModelElement ;
3329
34- import io .vavr .Tuple ;
35-
3630/**
3731 * A utility class for grouping model URIs by namespace and version.
3832 */
3933public class ModelGroupingUtils {
40-
4134 private final AspectModelLoader aspectModelLoader ;
42- private final Path modelPath ;
4335
4436 /**
4537 * Constructs a ModelGrouper with the given base model path.
4638 *
4739 * @param aspectModelLoader the loader for aspect models
48- * @param modelPath the base path to relativize URIs against
4940 */
50- public ModelGroupingUtils ( final AspectModelLoader aspectModelLoader , final Path modelPath ) {
41+ public ModelGroupingUtils ( final AspectModelLoader aspectModelLoader ) {
5142 this .aspectModelLoader = aspectModelLoader ;
52- this .modelPath = modelPath ;
5343 }
5444
5545 /**
@@ -59,136 +49,21 @@ public ModelGroupingUtils( final AspectModelLoader aspectModelLoader, final Path
5949 * @return a map where the keys are namespaces and the values are lists of maps containing versions and their associated models
6050 */
6151 public Map <String , List <Version >> groupModelsByNamespaceAndVersion ( final Stream <URI > uriStream ) {
62- final List <URI > sortedUris = uriStream
63- .sorted ( Comparator .comparing ( uri -> modelPath .relativize ( Paths .get ( uri ) ).toString () ) )
64- .toList ();
65-
66- return sortedUris .stream ()
67- .map ( this ::relativizePath )
68- .map ( relativePath -> {
69- final AspectModel aspectModel = ModelUtils .loadModelFromFile ( modelPath , relativePath , this .aspectModelLoader );
70-
71- final ModelElement modelElement = !aspectModel .aspects ().isEmpty ()
72- ? aspectModel .aspect ()
73- : aspectModel .files ().stream ()
74- .flatMap ( file -> file .elements ().stream () )
75- .findFirst ()
76- .orElse ( null );
77-
78- return Tuple .of ( modelElement , splitPath ( relativePath ) );
79- } )
80- .collect ( Collectors .groupingBy (
81- tuple -> extractNamespace ( tuple ._2 ),
82- TreeMap ::new ,
83- Collectors .collectingAndThen (
84- Collectors .groupingBy (
85- tuple -> extractVersion ( tuple ._2 ),
86- Collectors .mapping (
87- tuple -> {
88- final String [] parts = tuple ._2 ;
89- final Path resolvedPath = Paths .get ( parts [0 ], parts [1 ], parts [2 ] );
90- final boolean fileExists = modelPath .resolve ( resolvedPath ).toFile ().exists ();
91- return createModel ( parts , fileExists , tuple ._1 );
92- },
93- Collectors .toList ()
94- )
95- ),
96- this ::convertAndSortVersionMap
97- )
98- ) );
99- }
100-
101- /**
102- * Relativizes the given URI against the base model path.
103- *
104- * @param uri the URI to relativize
105- * @return the relativized path as a string
106- */
107- private String relativizePath ( final URI uri ) {
108- return modelPath .relativize ( Path .of ( uri ) ).toString ();
109- }
110-
111- /**
112- * Splits the given path string into parts using the file separator.
113- *
114- * @param path the path string to split
115- * @return an array of path parts
116- */
117- private String [] splitPath ( final String path ) {
118- return path .split ( Pattern .quote ( File .separator ) );
119- }
120-
121- /**
122- * Extracts the namespace from the given path parts.
123- *
124- * @param parts an array of path parts
125- * @return the namespace (first part of the path)
126- */
127- private String extractNamespace ( final String [] parts ) {
128- return parts [0 ];
129- }
130-
131- /**
132- * Extracts the version from the given path parts.
133- *
134- * @param parts an array of path parts
135- * @return the version (second part of the path)
136- */
137- private String extractVersion ( final String [] parts ) {
138- return parts [1 ];
139- }
140-
141- /**
142- * Creates a map representing a model from the given path parts, setting the existing field as specified.
143- *
144- * @param parts an array of path parts
145- * @param modelElement an element of the aspect model
146- * @param existing whether to set the existing field to true
147- * @return a map containing the model information
148- */
149- private Model createModel ( final String [] parts , final boolean existing , final ModelElement modelElement ) {
150- return new Model ( parts [2 ], modelElement .urn (), existing );
151- }
152-
153- /**
154- * Converts a version-to-models map into a list of sorted Version objects.
155- *
156- * @param versionMap a map where keys are versions and values are lists of Model objects
157- * @return a list of Version objects sorted by semantic version
158- */
159- private List <Version > convertAndSortVersionMap ( final Map <String , List <Model >> versionMap ) {
160- return versionMap .entrySet ().stream ().sorted ( Map .Entry .comparingByKey ( this ::compareSemanticVersions ) )
161- .map ( entry -> new Version ( entry .getKey (), sortModelsAlphabetically ( entry .getValue () ) ) ).collect ( Collectors .toList () );
162- }
163-
164- /**
165- * Sorts a list of models alphabetically by their names.
166- *
167- * @param models the list of models to sort
168- * @return a sorted list of models
169- */
170- private List <Model > sortModelsAlphabetically ( final List <Model > models ) {
171- return models .stream ().sorted ( Comparator .comparing ( Model ::getModel ) ).collect ( Collectors .toList () );
172- }
173-
174- /**
175- * Compares two semantic version strings (e.g., "1.0.0" and "1.0.1").
176- *
177- * @param v1 the first version string
178- * @param v2 the second version string
179- * @return a negative number if v1 < v2, zero if v1 == v2, or a positive number if v1 > v2
180- */
181- private int compareSemanticVersions ( final String v1 , final String v2 ) {
182- final String [] parts1 = v1 .split ( "\\ ." );
183- final String [] parts2 = v2 .split ( "\\ ." );
184- for ( int i = 0 ; i < Math .max ( parts1 .length , parts2 .length ); i ++ ) {
185- final int part1 = i < parts1 .length ? Integer .parseInt ( parts1 [i ] ) : 0 ;
186- final int part2 = i < parts2 .length ? Integer .parseInt ( parts2 [i ] ) : 0 ;
187- final int comparison = Integer .compare ( part1 , part2 );
188- if ( comparison != 0 ) {
189- return comparison ;
190- }
191- }
192- return 0 ;
52+ return aspectModelLoader .load ( uriStream .map ( File ::new ).toList () ).files ().stream ()
53+ .flatMap ( aspectModelFile -> aspectModelFile .aspects ().stream ().map ( ModelElement .class ::cast ).findFirst ().or ( () ->
54+ aspectModelFile .elements ().stream ().filter ( modelElement -> !modelElement .isAnonymous () ).findAny () ).stream () )
55+ .map ( modelElement -> new Model ( modelElement .getSourceFile ().filename ().orElse ( "unnamed file" ), modelElement .urn (), true ) )
56+ .collect ( Collectors .groupingBy ( model -> model .getAspectModelUrn ().getNamespaceMainPart () ) )
57+ .entrySet ().stream ().sorted ( Map .Entry .comparingByKey () )
58+ .map ( modelsByNamespaceEntry -> Map .entry ( modelsByNamespaceEntry .getKey (),
59+ modelsByNamespaceEntry .getValue ().stream ()
60+ .collect ( Collectors .groupingBy ( model -> model .getAspectModelUrn ().getVersion () ) )
61+ .entrySet ().stream ().sorted ( Map .Entry .comparingByKey () )
62+ .map ( modelsByVersion -> new Version ( modelsByVersion .getKey (),
63+ modelsByVersion .getValue ().stream ().sorted ( Comparator .comparing ( Model ::getModel ) ).toList () ) )
64+ .toList () ) )
65+ .collect ( Collectors .toMap ( Map .Entry ::getKey , Map .Entry ::getValue , ( v1 , v2 ) -> {
66+ throw new RuntimeException ( String .format ( "Duplicate key for values %s and %s" , v1 , v2 ) );
67+ }, LinkedHashMap ::new ) );
19368 }
19469}
0 commit comments