Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
28ac6b3
Fix relativePath formatting in pom.xml
ma-mirzaei May 21, 2026
7929bc9
Fix relativePath formatting in pom.xml
ma-mirzaei Jun 16, 2026
ef44e20
Write test cases for vsumService and generateProjectArchive
ma-mirzaei Jun 16, 2026
335f117
reformat
ma-mirzaei Jun 16, 2026
d6da0fe
reformat
ma-mirzaei Jun 16, 2026
8785967
reformat
ma-mirzaei Jun 16, 2026
ece8b89
reformat
ma-mirzaei Jun 16, 2026
dfb429a
reformat
ma-mirzaei Jun 16, 2026
f8ff3bf
reformat
ma-mirzaei Jun 16, 2026
d6f3a02
added new api to get exact java jar file
ma-mirzaei Jun 17, 2026
cebc79e
add sonar.projectKey
ma-mirzaei Jun 22, 2026
c1ae366
Merge pull request #17 from vitruv-tools/get-java-jar
ma-mirzaei Jun 22, 2026
722aac7
reformat: update method
ma-mirzaei Jun 22, 2026
1e32f05
remove unnecessary test cases
ma-mirzaei Jun 22, 2026
d8261f6
reformat
ma-mirzaei Jun 22, 2026
86b73bd
reformat
ma-mirzaei Jun 22, 2026
2335f4d
Use try-with-resources or close this "Stream" in a "finally" clause
ma-mirzaei Jun 22, 2026
b4df818
Disable access to external entities in XML parsing.
ma-mirzaei Jun 22, 2026
d7747b6
Merge pull request #12 from vitruv-tools/build-project
ma-mirzaei Jun 24, 2026
1bd8f41
modify Dockerfile
ma-mirzaei Jun 24, 2026
9fcbb57
modify Dockerfile and
ma-mirzaei Jun 24, 2026
f5a9601
Refactor exception handling in GlobalExceptionHandler and improve err…
ma-mirzaei Jul 10, 2026
9ad6348
Refactor error response handling in GlobalExceptionHandler for improv…
ma-mirzaei Jul 10, 2026
d8cb1c9
Merge pull request #20 from vitruv-tools/throw-exception-message
ma-mirzaei Jul 14, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .mvn/wrapper/maven-wrapper.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
wrapperVersion=3.3.4
distributionType=only-script
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.11/apache-maven-3.9.11-bin.zip
20 changes: 5 additions & 15 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,21 +1,11 @@
FROM eclipse-temurin:25-jdk AS build
WORKDIR /workspace
FROM eclipse-temurin:21-jdk

RUN apt-get update \
&& apt-get install -y --no-install-recommends maven \
&& rm -rf /var/lib/apt/lists/*
&& apt-get install -y maven \
&& rm -rf /var/lib/apt/lists/*

COPY pom.xml .
COPY src ./src

RUN mvn -q -DskipTests package

FROM eclipse-temurin:25-jre
WORKDIR /app

COPY --from=build /workspace/target/*.jar app.jar
COPY methodologist-setup-service-0.0.1-SNAPSHOT.jar /app/app.jar

EXPOSE 8090

ENTRYPOINT ["java", "-jar", "/app/app.jar"]

ENTRYPOINT ["java", "-jar", "/app/app.jar"]
13 changes: 11 additions & 2 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>4.0.6</version>
<relativePath/> <!-- lookup parent from repository -->
<relativePath/>
</parent>
<groupId>tools.vitruv</groupId>
<artifactId>methodologist-setup-service</artifactId>
Expand All @@ -28,8 +28,17 @@
</scm>
<properties>
<java.version>21</java.version>

<sonar.host.url>https://sonarcloud.io</sonar.host.url>
<sonar.organization>vitruv-tools</sonar.organization>
<sonar.projectKey>vitruv-tools_Methodologist-SetupService</sonar.projectKey>

</properties>
<dependencies>
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
Expand Down Expand Up @@ -109,7 +118,7 @@
<configuration>
<java>
<googleJavaFormat>
<version>1.22.0</version>
<version>1.28.0</version>
<style>GOOGLE</style>
</googleJavaFormat>
</java>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package tools.vitruv.methodologist.setup.config;

import java.net.URL;
import java.net.URLClassLoader;

/** The CustomClassLoader class is used to load classes from a custom classpath. */
public class CustomClassLoader extends URLClassLoader {
/**
* The constructor of the CustomClassLoader class.
*
* @param urls The URLs of the classpath.
* @param parent The parent class loader.
*/
public CustomClassLoader(URL[] urls, ClassLoader parent) {
super(urls, parent);
}

/**
* Adds a JAR file to the classpath.
*
* @param url The URL of the JAR file.
*/
public void addJar(URL url) {
this.addURL(url);
}
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
package tools.vitruv.methodologist.setup.config;

import lombok.RequiredArgsConstructor;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.nio.file.NoSuchFileException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.context.request.WebRequest;
import tools.vitruv.methodologist.setup.exception.ErrorResponseDTO;
import tools.vitruv.methodologist.setup.exception.GenmodelException;
import tools.vitruv.methodologist.setup.exception.MethodologistSetupException;
Expand All @@ -18,77 +20,95 @@
*/
@Slf4j
@RestControllerAdvice(basePackages = "tools.vitruv.methodologist.setup")
@RequiredArgsConstructor
public class GlobalExceptionHandler {
private final ObjectMapper objectMapper = new ObjectMapper();

/**
* Handles MethodologistSetupException.
*
* @param ex the exception
* @param request the web request
* @return error response
*/
@ExceptionHandler(MethodologistSetupException.class)
public ResponseEntity<ErrorResponseDTO> handleMethodologistSetupException(
MethodologistSetupException ex, WebRequest request) {
public void handleMethodologistSetupException(
MethodologistSetupException ex, HttpServletRequest request, HttpServletResponse response)
throws IOException {
log.error("MethodologistSetupException occurred: {}", ex.getMessage(), ex);

ErrorResponseDTO errorResponse =
ErrorResponseDTO.builder()
.errorCode(ex.getErrorCode())
.message(ex.getMessage())
.status(HttpStatus.BAD_REQUEST.value())
.timestamp(System.currentTimeMillis())
.path(request.getDescription(false).replace("uri=", ""))
.build();

return new ResponseEntity<>(errorResponse, HttpStatus.BAD_REQUEST);
writeErrorResponse(
response, request, HttpStatus.BAD_REQUEST, ex.getErrorCode(), ex.getMessage());
}

/**
* Handles GenmodelException.
*
* @param ex the exception
* @param request the web request
* @return error response
*/
@ExceptionHandler(GenmodelException.class)
public ResponseEntity<ErrorResponseDTO> handleGenmodelException(
GenmodelException ex, WebRequest request) {
public void handleGenmodelException(
GenmodelException ex, HttpServletRequest request, HttpServletResponse response)
throws IOException {
log.error("GenmodelException occurred: {}", ex.getMessage(), ex);

ErrorResponseDTO errorResponse =
ErrorResponseDTO.builder()
.errorCode(ex.getErrorCode())
.message(ex.getMessage())
.status(HttpStatus.UNPROCESSABLE_ENTITY.value())
.timestamp(System.currentTimeMillis())
.path(request.getDescription(false).replace("uri=", ""))
.build();
writeErrorResponse(
response, request, HttpStatus.UNPROCESSABLE_ENTITY, ex.getErrorCode(), ex.getMessage());
}

return new ResponseEntity<>(errorResponse, HttpStatus.UNPROCESSABLE_ENTITY);
/**
* Handles NoSuchFileException raised when an expected build artifact is missing.
*
* @param ex the exception
* @param request the web request
*/
@ExceptionHandler(NoSuchFileException.class)
public void handleNoSuchFileException(
NoSuchFileException ex, HttpServletRequest request, HttpServletResponse response)
throws IOException {
log.error("NoSuchFileException occurred: {}", ex.getMessage(), ex);

writeErrorResponse(
response, request, HttpStatus.BAD_REQUEST, "VSUM_ARTIFACT_NOT_FOUND", ex.getMessage());
}

/**
* Handles all other exceptions.
*
* @param ex the exception
* @param request the web request
* @return error response
*/
@ExceptionHandler(Exception.class)
public ResponseEntity<ErrorResponseDTO> handleGlobalException(Exception ex, WebRequest request) {
public void handleGlobalException(
Exception ex, HttpServletRequest request, HttpServletResponse response) throws IOException {
log.error("Unexpected exception occurred: {}", ex.getMessage(), ex);

writeErrorResponse(
response,
request,
HttpStatus.INTERNAL_SERVER_ERROR,
"INTERNAL_ERROR",
ErrorMessages.UNEXPECTED_ERROR);
}

private void writeErrorResponse(
HttpServletResponse response,
HttpServletRequest request,
HttpStatus status,
String errorCode,
String message)
throws IOException {
ErrorResponseDTO errorResponse =
ErrorResponseDTO.builder()
.errorCode("INTERNAL_ERROR")
.message(ErrorMessages.UNEXPECTED_ERROR)
.status(HttpStatus.INTERNAL_SERVER_ERROR.value())
.errorCode(errorCode)
.message(message)
.status(status.value())
.timestamp(System.currentTimeMillis())
.path(request.getDescription(false).replace("uri=", ""))
.path(request.getRequestURI())
.build();

return new ResponseEntity<>(errorResponse, HttpStatus.INTERNAL_SERVER_ERROR);
response.setStatus(status.value());
response.setCharacterEncoding("UTF-8");
response.setContentType("application/json");
response.getWriter().write(objectMapper.writeValueAsString(errorResponse));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package tools.vitruv.methodologist.setup.config;

import java.io.File;

/**
* The MetamodelLocation class is used to store the location of a metamodel and its corresponding
* genmodel.
*/
public record MetamodelLocation(
File metamodel, File genmodel, String genmodelUri, String modelDirectory) {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
package tools.vitruv.methodologist.setup.config;

import java.io.File;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.emf.codegen.ecore.genmodel.GenModel;
import org.eclipse.emf.codegen.ecore.genmodel.GenModelPackage;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EPackage;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl;
import org.eclipse.emf.ecore.xmi.impl.XMIResourceFactoryImpl;

/** The VitruvConfiguration class is used to store the configuration of the Vitruv CLI. */
@Slf4j
public class VitruvConfiguration {

/** -- GETTER -- Returns the model names. */
@Getter private final List<String> modelNames = new ArrayList<>();

private final List<MetamodelLocation> metamodelLocations = new ArrayList<>();

/** -- GETTER -- Returns the reaction file locations used by the CLI. */
@Getter private final List<Path> reactionLocations = new ArrayList<>();

/**
* -- SETTER -- Sets the local path of the configuration.
*
* <p>-- GETTER -- Returns the local path of the configuration.
*/
@Getter @Setter private Path localPath;

/** -- GETTER -- Returns the package name. */
@Getter private String packageName;

/**
* -- SETTER -- Sets the workflow of the configuration.
*
* <p>-- GETTER -- Returns the workflow of the configuration.
*/
@Getter @Setter private File workflow;

/**
* Removes the last segment of a string.
*
* @param input The input string.
* @return The input string without the last segment.
*/
public static String removeLastSegment(String input) {
int lastDotIndex = input.lastIndexOf('.');
if (lastDotIndex == -1) {
return input;
}
return input.substring(0, lastDotIndex);
}

/**
* Adds a metamodel location to the configuration.
*
* @param metamodelLocation The metamodel location to add.
*/
public void addMetamodelLocations(MetamodelLocation metamodelLocation) {
this.metamodelLocations.add(metamodelLocation);
}

/**
* Sets the reaction file locations used by the CLI.
*
* @param reactionLocations list of paths to reaction files.
*/
public void setReactionLocations(List<Path> reactionLocations) {
this.reactionLocations.clear();
if (reactionLocations != null) {
this.reactionLocations.addAll(reactionLocations);
}
}

/**
* Returns the metamodel locations.
*
* @return The metamodel locations.
*/
public List<MetamodelLocation> getMetaModelLocations() {
return this.metamodelLocations;
}

/**
* Sets the metamodel locations using a semicolon-separated list of {@code ecore,genmodel} pairs.
*
* @param paths The metamodel argument string.
*/
public void setMetaModelLocations(String paths) {
Resource.Factory.Registry reg = Resource.Factory.Registry.INSTANCE;
reg.getExtensionToFactoryMap().put("ecore", new XMIResourceFactoryImpl());
reg.getExtensionToFactoryMap().put("genmodel", new XMIResourceFactoryImpl());

GenModelPackage.eINSTANCE.eClass();

for (String modelPaths : paths.split(";")) {
String metamodelPath = modelPaths.split(",")[0];
String genmodelPath = modelPaths.split(",")[1];

File metamodel = new File(metamodelPath);
File genmodel = new File(genmodelPath);

String localModelDirectory = "";

ResourceSet resourceSet = new ResourceSetImpl();
URI uri = URI.createFileURI(metamodel.getAbsolutePath().trim());
Resource resource = resourceSet.getResource(uri, true);
String nsUri = "";
if (!resource.getContents().isEmpty()
&& resource.getContents().get(0) instanceof EPackage ePackage) {
URI genmodelURI = URI.createFileURI(genmodel.getAbsolutePath());
nsUri = genmodelURI.toString();
Resource genmodelResource = resourceSet.getResource(genmodelURI, true);
modelNames.add(ePackage.getName());
if (!genmodelResource.getContents().isEmpty()
&& genmodelResource.getContents().get(0) instanceof GenModel genModel) {
String packageString = removeLastSegment(genModel.getModelPluginID());
log.info("--------------------->>>> " + packageString);
this.setPackageName(packageString);
localModelDirectory = genModel.getModelDirectory();
}
}

this.addMetamodelLocations(
new MetamodelLocation(metamodel, genmodel, nsUri, localModelDirectory));
}
}

/**
* Sets the package name.
*
* @param packageName The package name.
*/
public void setPackageName(String packageName) {
this.packageName = packageName.replace("\\s", "");
}
}
Loading