2121import java .nio .file .Files ;
2222import java .nio .file .Path ;
2323import java .nio .file .Paths ;
24+ import java .util .List ;
25+ import java .util .function .Predicate ;
2426import java .util .function .Supplier ;
2527import java .util .stream .StreamSupport ;
2628
29+ import org .eclipse .esmf .ame .exceptions .CreateFileException ;
2730import org .eclipse .esmf .ame .exceptions .FileHandlingException ;
2831import org .eclipse .esmf .ame .exceptions .FileReadException ;
32+ import org .eclipse .esmf .aspectmodel .AspectLoadingException ;
2933import org .eclipse .esmf .aspectmodel .AspectModelFile ;
3034import org .eclipse .esmf .aspectmodel .loader .AspectModelLoader ;
35+ import org .eclipse .esmf .aspectmodel .resolver .exceptions .ModelResolutionException ;
36+ import org .eclipse .esmf .aspectmodel .shacl .violation .Violation ;
3137import org .eclipse .esmf .aspectmodel .urn .AspectModelUrn ;
3238import org .eclipse .esmf .metamodel .AspectModel ;
39+ import org .eclipse .esmf .metamodel .ModelElement ;
3340
3441import io .micronaut .http .multipart .CompletedFileUpload ;
3542import jakarta .annotation .Nonnull ;
@@ -77,22 +84,32 @@ public static void deleteFileSafely( @Nonnull final File file ) {
7784 }
7885
7986 /**
80- * Creates a file based on the given AspectModelUrn.
87+ * Creates a new file for the given AspectModelUrn and file name in the specified storage path.
88+ * If necessary, parent directories are created.
8189 *
82- * @param aspectModelUrn - The Aspect Model URN.
83- * @param fileName - The name of the Aspect Model file.
84- * @return The created file.
85- * @throws IOException if an I/O error occurs.
90+ * @param aspectModelUrn the Aspect Model URN
91+ * @param fileName the name of the file to create
92+ * @param storagePath the base storage path
93+ * @throws IOException if an I/O error occurs during creation
8694 */
87- public static File createFile ( final AspectModelUrn aspectModelUrn , final String fileName , final Path storagePath ) throws IOException {
95+ public static void createFile ( final AspectModelUrn aspectModelUrn , final String fileName , final Path storagePath ) throws IOException {
8896 final Path filePath = createFilePath ( aspectModelUrn , fileName , storagePath );
97+ createFile ( filePath );
98+ }
8999
100+ /**
101+ * Creates a file at the specified path, including any necessary parent directories.
102+ * Logs the creation process.
103+ *
104+ * @param filePath the path of the file to create
105+ * @throws IOException if an I/O error occurs during creation
106+ */
107+ public static void createFile ( final Path filePath ) throws IOException {
90108 try {
91109 if ( Files .notExists ( filePath .getParent () ) ) {
92110 Files .createDirectories ( filePath .getParent () );
93111 LOG .info ( "Directories created: {}" , filePath .getParent () );
94112 }
95-
96113 if ( Files .notExists ( filePath ) ) {
97114 Files .createFile ( filePath );
98115 LOG .info ( "File created: {}" , filePath );
@@ -103,8 +120,6 @@ public static File createFile( final AspectModelUrn aspectModelUrn, final String
103120 LOG .error ( "Failed to create file: {}" , filePath , e );
104121 throw e ;
105122 }
106-
107- return filePath .toFile ();
108123 }
109124
110125 /**
@@ -160,9 +175,37 @@ public static InputStream openInputStreamFromUpload( final CompletedFileUpload a
160175 */
161176 public static Supplier <AspectModel > getAspectModelSupplier ( final String turtleData , final File newFile ,
162177 final AspectModelLoader aspectModelLoader ) {
163- final ByteArrayInputStream inputStream = new ByteArrayInputStream ( turtleData .getBytes ( StandardCharsets .UTF_8 ) );
178+ return createLazySupplier ( () -> {
179+ try ( final ByteArrayInputStream inputStream = new ByteArrayInputStream ( turtleData .getBytes ( StandardCharsets .UTF_8 ) ) ) {
180+ final AspectModel aspectModel = aspectModelLoader .load ( inputStream , newFile .toURI () );
181+ checkForDuplicateFiles ( aspectModel , newFile .getName () );
182+ return aspectModel ;
183+ } catch ( final IOException e ) {
184+ throw new CreateFileException ( "Failed to process Turtle data" , e );
185+ }
186+ } );
187+ }
188+
189+ private static void checkForDuplicateFiles ( final AspectModel aspectModel ,
190+ final String sourceFilename ) {
191+
192+ final boolean hasDifferentFile = aspectModel .elements ().stream ()
193+ .filter ( modelElement -> modelElement .getSourceFile ().filename ().orElse ( "" ).equals ( sourceFilename ) )
194+ .anyMatch ( modelElement -> hasDifferentFileForElement ( modelElement , sourceFilename ) );
195+
196+ if ( hasDifferentFile ) {
197+ LOG .warn ( "Some elements are already defined in the same namespace" );
198+ throw new CreateFileException ( "Some elements are already defined in the same namespace" );
199+ }
200+ }
164201
165- return createLazySupplier ( () -> aspectModelLoader .load ( inputStream , newFile .toURI () ) );
202+ private static boolean hasDifferentFileForElement ( final ModelElement modelElement , final String sourceFilename ) {
203+ try {
204+ final String modelSourceFileName = modelElement .getSourceFile ().filename ().orElse ( "" );
205+ return !modelSourceFileName .equals ( sourceFilename );
206+ } catch ( final ModelResolutionException | AspectLoadingException ex ) {
207+ return false ;
208+ }
166209 }
167210
168211 private static Supplier <AspectModel > createLazySupplier ( final Supplier <AspectModel > loader ) {
@@ -181,14 +224,43 @@ public AspectModel get() {
181224 };
182225 }
183226
227+ /**
228+ * Loads an {@link AspectModel} from a file path by constructing the full model path.
229+ *
230+ * @param modelPath the base path to the model storage directory
231+ * @param filePath the relative file path (namespace/version/modelName)
232+ * @param aspectModelLoader the loader to load the {@link AspectModel}
233+ * @return the loaded {@link AspectModel}
234+ */
184235 public static AspectModel loadModelFromFile ( final Path modelPath , final String filePath , final AspectModelLoader aspectModelLoader ) {
185236 final Path path = Paths .get ( filePath ).normalize ();
186237 final String [] pathParts = StreamSupport .stream ( path .spliterator (), false ).map ( Path ::toString ).toArray ( String []::new );
187238 final Path aspectModelPath = constructModelPath ( modelPath , pathParts [0 ], pathParts [1 ], pathParts [2 ] );
188239 return aspectModelLoader .load ( aspectModelPath .toFile () );
189240 }
190241
242+ /**
243+ * Constructs a model file path from the given components.
244+ *
245+ * @param modelPath the base path to the model storage directory
246+ * @param namespace the namespace part of the model
247+ * @param version the version part of the model
248+ * @param modelName the name of the model file
249+ * @return the constructed {@link Path}
250+ */
191251 public static Path constructModelPath ( final Path modelPath , final String namespace , final String version , final String modelName ) {
192252 return Path .of ( modelPath .toString (), namespace , version , modelName );
193253 }
254+
255+ /**
256+ * Throws the given exception if any violation in the list matches the predicate.
257+ *
258+ * @param violations the list of {@link Violation} objects to check
259+ * @param predicate the predicate to filter violations
260+ * @param exception the exception to throw if a matching violation is found
261+ */
262+ public static void throwIfViolationPresent ( final List <Violation > violations , final Predicate <Violation > predicate ,
263+ final RuntimeException exception ) {
264+ violations .stream ().filter ( predicate ).findFirst ().ifPresent ( v -> {throw exception ;} );
265+ }
194266}
0 commit comments