-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
5 changed files
with
204 additions
and
0 deletions.
There are no files selected for viewing
65 changes: 65 additions & 0 deletions
65
restAPI/src/main/java/restAPI/architecture_analysis/ArchitectureAnalysisController.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
package restAPI.architecture_analysis; | ||
|
||
import com.google.common.collect.ArrayListMultimap; | ||
import com.google.common.collect.Multimap; | ||
import org.apache.commons.io.FileUtils; | ||
import org.slf4j.Logger; | ||
import org.slf4j.LoggerFactory; | ||
import org.springframework.beans.factory.annotation.Autowired; | ||
import org.springframework.http.HttpStatus; | ||
import org.springframework.http.ResponseEntity; | ||
import org.springframework.web.bind.annotation.PostMapping; | ||
import org.springframework.web.bind.annotation.RequestParam; | ||
import org.springframework.web.bind.annotation.RestController; | ||
import org.springframework.web.multipart.MultipartFile; | ||
import restAPI.util.TempFileUtils; | ||
|
||
import java.io.IOException; | ||
import java.nio.file.Path; | ||
|
||
@RestController | ||
public class ArchitectureAnalysisController { | ||
public static final String architectureFieldName = "architecture"; | ||
private final ArchitectureAnalysisService architectureAnalysisService; | ||
|
||
Logger logger = LoggerFactory.getLogger(ArchitectureAnalysisController.class); | ||
|
||
@Autowired | ||
public ArchitectureAnalysisController(ArchitectureAnalysisService architectureAnalysisService) { | ||
this.architectureAnalysisService = architectureAnalysisService; | ||
} | ||
|
||
@PostMapping("/analyze/upload") | ||
public ResponseEntity<String> handleMultipleFilesUpload( | ||
@RequestParam("architectures") MultipartFile[] architectures) throws IOException { | ||
return runSimulation(architectures); | ||
} | ||
|
||
// TODO: Handle this call in a non-blocking manner, taking into account that this implementation is not | ||
// client friendly as it can time-out the request due to the long processing time. | ||
private ResponseEntity<String> runSimulation(MultipartFile[] architectures) throws IOException { | ||
Path tmpFolder = null; | ||
try { | ||
tmpFolder = TempFileUtils.createDefaultTempDir("architecture-analysis"); | ||
Multimap<String, String> savedFiles = saveArchitectureFile(architectures, tmpFolder); | ||
var response = architectureAnalysisService.runAnalysis(savedFiles); | ||
return new ResponseEntity<>(response.toJSON(), HttpStatus.OK); | ||
} catch (Exception e) { | ||
String errorMessage = e.getMessage(); | ||
logger.error(errorMessage); | ||
return new ResponseEntity<>(errorMessage, HttpStatus.INTERNAL_SERVER_ERROR); | ||
} finally { | ||
// Do the clean-up | ||
if (tmpFolder != null) { | ||
FileUtils.deleteDirectory(tmpFolder.toFile()); | ||
} | ||
} | ||
} | ||
|
||
private Multimap<String, String> saveArchitectureFile(MultipartFile[] architectures, Path tmpFolder) { | ||
Multimap<String, String> savedFiles = ArrayListMultimap.create(); | ||
savedFiles = TempFileUtils.saveFile(savedFiles, architectureFieldName, architectures, tmpFolder); | ||
return savedFiles; | ||
} | ||
|
||
} |
25 changes: 25 additions & 0 deletions
25
.../main/java/restAPI/architecture_analysis/ArchitectureAnalysisExperimentFileGenerator.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
package restAPI.architecture_analysis; | ||
|
||
import java.io.File; | ||
import java.io.FileWriter; | ||
import java.io.IOException; | ||
|
||
public class ArchitectureAnalysisExperimentFileGenerator { | ||
private static final String experimentJSON = """ | ||
{ | ||
"simulation_metadata": { | ||
"experiment_name": "Architecture-Only-Experiment", | ||
"model_name": "Architecture-Only-Model", | ||
"duration": 0 | ||
} | ||
}"""; | ||
|
||
public File generateExperimentFile() throws IOException { | ||
File file = File.createTempFile("architecture-only-experiment", ".json"); | ||
FileWriter writer = new FileWriter(file); | ||
writer.write(experimentJSON); | ||
writer.close(); | ||
return file; | ||
} | ||
|
||
} |
77 changes: 77 additions & 0 deletions
77
restAPI/src/main/java/restAPI/architecture_analysis/ArchitectureAnalysisService.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
package restAPI.architecture_analysis; | ||
|
||
import cambio.simulator.ExperimentCreator; | ||
import cambio.simulator.ExperimentStartupConfig; | ||
import cambio.simulator.entities.NamedEntity; | ||
import cambio.simulator.entities.microservice.Microservice; | ||
import cambio.simulator.entities.microservice.Operation; | ||
import cambio.simulator.models.ArchitectureModel; | ||
import cambio.simulator.models.MiSimModel; | ||
import com.google.common.collect.Multimap; | ||
import desmoj.core.simulator.Experiment; | ||
import org.springframework.stereotype.Service; | ||
import restAPI.data_objects.ArchitectureAnalysisResponse; | ||
import restAPI.data_objects.ArchitectureAnalysisResponseImpl; | ||
|
||
import java.io.File; | ||
import java.io.IOException; | ||
import java.util.Collection; | ||
import java.util.HashSet; | ||
import java.util.Set; | ||
|
||
import static java.util.stream.Collectors.toSet; | ||
|
||
@Service | ||
public class ArchitectureAnalysisService { | ||
private final File experiment; | ||
|
||
public ArchitectureAnalysisService() throws IOException { | ||
this.experiment = (new ArchitectureAnalysisExperimentFileGenerator()).generateExperimentFile(); | ||
} | ||
|
||
public ArchitectureAnalysisResponse runAnalysis(Multimap<String, String> inputFiles) throws Exception { | ||
String archDescPath = getArchtectureDescPath(inputFiles); | ||
ArchitectureModelAdapter architectureModel = new ArchitectureModelAdapter(getArchitectureModel(archDescPath)); | ||
return new ArchitectureAnalysisResponseImpl(architectureModel.getServiceNames(), architectureModel.getEndpointNames()); | ||
} | ||
|
||
private String getArchtectureDescPath(Multimap<String, String> inputFiles) throws Exception { | ||
Collection<String> archDescPathCollection = inputFiles.get(ArchitectureAnalysisController.architectureFieldName); | ||
if (archDescPathCollection.isEmpty()) { | ||
throw new Exception("You have to provide an architecture description file."); | ||
} | ||
return archDescPathCollection.iterator().next(); | ||
} | ||
|
||
private ArchitectureModel getArchitectureModel(final String archDescPath) { | ||
ExperimentStartupConfig config = new ExperimentStartupConfig(archDescPath, experiment.getAbsolutePath(), | ||
null, null, null, false, | ||
false, false, null); | ||
Experiment experiment = (new ExperimentCreator()).createSimulationExperiment(config); | ||
MiSimModel model = (MiSimModel) experiment.getModel(); | ||
return model.getArchitectureModel(); | ||
} | ||
|
||
private static class ArchitectureModelAdapter { | ||
private final ArchitectureModel architectureModel; | ||
|
||
public ArchitectureModelAdapter(ArchitectureModel architectureModel) { | ||
this.architectureModel = architectureModel; | ||
} | ||
|
||
public Set<String> getServiceNames() { | ||
return architectureModel.getMicroservices().stream().map(NamedEntity::getPlainName).collect(toSet()); | ||
} | ||
|
||
public Set<String> getEndpointNames() { | ||
Set<String> names = new HashSet<>(); | ||
for (Microservice service : architectureModel.getMicroservices()) { | ||
for (Operation operation : service.getOperations()) { | ||
names.add(operation.getFullyQualifiedPlainName()); | ||
} | ||
} | ||
return names; | ||
} | ||
} | ||
|
||
} |
7 changes: 7 additions & 0 deletions
7
restAPI/src/main/java/restAPI/data_objects/ArchitectureAnalysisResponse.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
package restAPI.data_objects; | ||
|
||
import com.fasterxml.jackson.core.JsonProcessingException; | ||
|
||
public interface ArchitectureAnalysisResponse { | ||
String toJSON() throws JsonProcessingException; | ||
} |
30 changes: 30 additions & 0 deletions
30
restAPI/src/main/java/restAPI/data_objects/ArchitectureAnalysisResponseImpl.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
package restAPI.data_objects; | ||
|
||
import com.fasterxml.jackson.core.JsonProcessingException; | ||
import com.fasterxml.jackson.databind.ObjectMapper; | ||
|
||
import java.util.Set; | ||
|
||
public final class ArchitectureAnalysisResponseImpl implements ArchitectureAnalysisResponse { | ||
|
||
private final Set<String> serviceNames; | ||
private final Set<String> endpointNames; | ||
|
||
public ArchitectureAnalysisResponseImpl(Set<String> serviceNames, Set<String> endpointNames) { | ||
this.serviceNames = serviceNames; | ||
this.endpointNames = endpointNames; | ||
} | ||
|
||
@Override | ||
public String toJSON() throws JsonProcessingException { | ||
return new ObjectMapper().writeValueAsString(this); | ||
} | ||
|
||
public Set<String> getServiceNames() { | ||
return serviceNames; | ||
} | ||
|
||
public Set<String> getEndpointNames() { | ||
return endpointNames; | ||
} | ||
} |