Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
4e1040d
refactor: define /solve/... router
schweikart Jul 30, 2023
bc40263
feat: configure generic /solve API docs
schweikart Jul 30, 2023
99c9fe9
refactor: move solving implementation to SolveRouter
schweikart Jul 30, 2023
c77b0b9
refactor: move /sub-routines/... routes to functional router
schweikart Jul 30, 2023
faf1606
refactor: move /solvers/... endpoints to functional router
schweikart Jul 30, 2023
b099156
refactor: move meta solver settings endpoints to functional router
schweikart Jul 30, 2023
8c9c5bb
refactor: move GET /solve/... routes to functional router
schweikart Jul 30, 2023
a851a67
refactor: remove ProblemController
schweikart Jul 30, 2023
cfcd84c
fix: use monos for response bodies
schweikart Jul 30, 2023
7eb2c7a
fix: import required beans in api tests
schweikart Jul 30, 2023
000034d
style: reformat code
schweikart Jul 30, 2023
1b35f8e
chore: ignore further GAMS output files
schweikart Aug 1, 2023
3c5d08e
docs: add javadocs to routing components
schweikart Aug 1, 2023
baa581b
refactor: split up router by endpoint
schweikart Aug 1, 2023
5996734
fix: extend test duration
schweikart Aug 1, 2023
f59193e
refactor: de-duplicate route names in router code
schweikart Sep 2, 2023
8edab8d
refactor: fix typing of SolutionHandle#toStringSolution
schweikart Sep 2, 2023
83123d2
fix: re-enable CORS to allow frontend access
schweikart Sep 2, 2023
b0c11b7
refactor: split up feature model anomaly solver by anomalies
schweikart Aug 1, 2023
a8f50d7
refactor: remove unused FEATURE_MODEL_ANOMALY problem type
schweikart Sep 7, 2023
936a21c
refactor: rename feature model anomaly solvers for more clarity
schweikart Sep 7, 2023
14e77fc
refactor: remove redundant problem type spec in SubRoutineDefinition
schweikart Sep 8, 2023
110f763
Merge pull request #40 from ProvideQ/refactor/feature-model-anomaly
Elscrux Sep 8, 2023
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
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -48,3 +48,5 @@ gamslice.txt
# Listing files compiled from our GAMS scripts
*.lst
*.op2
gams/**/225a
*.out
4 changes: 2 additions & 2 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ repositories {
}

dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-webflux'
implementation 'org.springframework.boot:spring-boot-starter-validation'
implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.0.4'
implementation 'org.springdoc:springdoc-openapi-starter-webflux-ui:2.0.4'
implementation 'com.bpodgursky:jbool_expressions:1.24'
implementation files('lib/de.ovgu.featureide.lib.fm-v3.9.1.jar', 'lib/uvl-parser.jar')
testImplementation 'org.springframework.boot:spring-boot-starter-test'
Expand Down
53 changes: 53 additions & 0 deletions src/main/java/edu/kit/provideq/toolbox/MetaSolverProvider.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package edu.kit.provideq.toolbox;

import edu.kit.provideq.toolbox.meta.MetaSolver;
import edu.kit.provideq.toolbox.meta.ProblemType;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
import java.util.stream.Collectors;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;

/**
* The meta solver provide can be used to find all or specific {@link MetaSolver}s.
*/
@Component
public class MetaSolverProvider {
private final Map<ProblemType, MetaSolver<?, ?, ?>> metaSolvers;

/**
* Initializes a meta solver provider bean.
* This provider will fetch available meta solvers once through the given {@code context}.
*
* @param context used to find available meta solvers.
*/
@Autowired
public MetaSolverProvider(ApplicationContext context) {
this.metaSolvers =
context.getBeansOfType(MetaSolver.class)
.values()
.stream()
.collect(Collectors.toMap(
MetaSolver::getProblemType,
metaSolver -> (MetaSolver<?, ?, ?>) metaSolver));
}

/**
* Finds a meta solver for the given problem type.
*
* @param problemType the type of problem to find the meta solver of.
* @return the meta solver that manages solvers of the given type.
*/
public MetaSolver<?, ?, ?> getMetaSolver(ProblemType problemType) {
return metaSolvers.get(problemType);
}

/**
* Returns all registered meta solvers for all available problem types.
*/
public Collection<MetaSolver<?, ?, ?>> getMetaSolvers() {
return Collections.unmodifiableCollection(metaSolvers.values());
}
}
103 changes: 0 additions & 103 deletions src/main/java/edu/kit/provideq/toolbox/ProblemController.java

This file was deleted.

This file was deleted.

4 changes: 2 additions & 2 deletions src/main/java/edu/kit/provideq/toolbox/Solution.java
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ public void setStatus(SolutionStatus newStatus) {
}

@Override
public SolutionHandle toStringSolution() {
public Solution<String> toStringSolution() {
return toStringSolution(Object::toString);
}

Expand All @@ -58,7 +58,7 @@ public SolutionHandle toStringSolution() {
* to a String.
* @return the solution with the stringified solution data.
*/
public SolutionHandle toStringSolution(@NotNull Function<S, String> stringSelector) {
public Solution<String> toStringSolution(@NotNull Function<S, String> stringSelector) {
Objects.requireNonNull(stringSelector, "Missing String selector!");

var stringSolution = new Solution<String>(getId());
Expand Down
5 changes: 4 additions & 1 deletion src/main/java/edu/kit/provideq/toolbox/SolutionHandle.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,8 @@ public interface SolutionHandle {

void setStatus(SolutionStatus newStatus);

SolutionHandle toStringSolution();
/**
* Converts this solution handle to a string-based {@link Solution}.
*/
Solution<String> toStringSolution();
}
21 changes: 8 additions & 13 deletions src/main/java/edu/kit/provideq/toolbox/SubRoutinePool.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package edu.kit.provideq.toolbox;

import edu.kit.provideq.toolbox.meta.MetaSolver;
import edu.kit.provideq.toolbox.meta.ProblemSolver;
import edu.kit.provideq.toolbox.meta.ProblemType;
import java.util.Collections;
Expand All @@ -15,7 +16,7 @@
public class SubRoutinePool {
private final Map<ProblemType, SolveRequest<?>> subRoutineCalls;

private ProblemControllerProvider problemControllerProvider;
private MetaSolverProvider metaSolverProvider;

public SubRoutinePool() {
subRoutineCalls = Collections.emptyMap();
Expand All @@ -31,8 +32,8 @@ public SubRoutinePool(Map<ProblemType, SolveRequest<?>> requestedSubRoutines) {
}

@Autowired
public void setProblemControllerProvider(ProblemControllerProvider problemControllerProvider) {
this.problemControllerProvider = problemControllerProvider;
public void setProblemControllerProvider(MetaSolverProvider metaSolverProvider) {
this.metaSolverProvider = metaSolverProvider;
}

/**
Expand All @@ -53,16 +54,10 @@ public <ProblemT, SolutionT> Function<ProblemT, Solution<SolutionT>> getSubRouti

var newSolveRequest = subRoutine.replaceContent(content);

ProblemController<
ProblemT,
SolutionT,
? extends ProblemSolver<ProblemT, SolutionT>> problemController
= (ProblemController<
ProblemT,
SolutionT,
? extends ProblemSolver<ProblemT, SolutionT>>)
problemControllerProvider.getProblemController(problemType);
return problemController.solve(newSolveRequest);
MetaSolver<ProblemT, SolutionT, ? extends ProblemSolver<ProblemT, SolutionT>> metaSolver =
(MetaSolver<ProblemT, SolutionT, ? extends ProblemSolver<ProblemT, SolutionT>>)
metaSolverProvider.getMetaSolver(problemType);
return metaSolver.solve(newSolveRequest);
};
}
}
19 changes: 19 additions & 0 deletions src/main/java/edu/kit/provideq/toolbox/api/CorsConfiguration.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package edu.kit.provideq.toolbox.api;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.reactive.config.CorsRegistry;
import org.springframework.web.reactive.config.EnableWebFlux;
import org.springframework.web.reactive.config.WebFluxConfigurer;

/**
* Spring configuration to enable CORS between the API and the web frontend.
*/
@Configuration
@EnableWebFlux
public class CorsConfiguration implements WebFluxConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package edu.kit.provideq.toolbox.api;

import static org.springdoc.core.fn.builders.apiresponse.Builder.responseBuilder;
import static org.springdoc.core.fn.builders.arrayschema.Builder.arraySchemaBuilder;
import static org.springdoc.core.fn.builders.content.Builder.contentBuilder;
import static org.springdoc.core.fn.builders.schema.Builder.schemaBuilder;
import static org.springdoc.webflux.core.fn.SpringdocRouteBuilder.route;
import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
import static org.springframework.web.reactive.function.server.ServerResponse.ok;

import edu.kit.provideq.toolbox.MetaSolverProvider;
import edu.kit.provideq.toolbox.meta.MetaSolver;
import edu.kit.provideq.toolbox.meta.ProblemType;
import edu.kit.provideq.toolbox.meta.setting.MetaSolverSetting;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.HttpStatus;
import org.springframework.web.reactive.config.EnableWebFlux;
import org.springframework.web.reactive.function.server.RouterFunction;
import org.springframework.web.reactive.function.server.ServerResponse;
import reactor.core.publisher.Mono;

/**
* This router handles requests to the GET {@code /meta-solver/{problemType}/settings} endpoints.
* Responses are generated from the settings reported by the available meta-solvers
* (see {@link MetaSolver#getSettings()}).
*/
@Configuration
@EnableWebFlux
public class MetaSolverSettingsRouter {
private final MetaSolverProvider metaSolverProvider;

@Autowired
public MetaSolverSettingsRouter(MetaSolverProvider metaSolverProvider) {
this.metaSolverProvider = metaSolverProvider;
}

@Bean
RouterFunction<ServerResponse> getMetaSolverSettingsRoutes() {
return metaSolverProvider.getMetaSolvers().stream()
.map(this::defineMetaSolverSettingsRouteForMetaSolver)
.reduce(RouterFunction::and)
.orElseThrow();
}

private RouterFunction<ServerResponse> defineMetaSolverSettingsRouteForMetaSolver(
MetaSolver<?, ?, ?> metaSolver) {
var problemType = metaSolver.getProblemType();
return route().GET(
getRouteForProblemType(problemType),
req -> handleMetaSolverSettingsRouteForMetaSolver(metaSolver),
ops -> ops
.operationId(getRouteForProblemType(problemType))
.tag(problemType.getId())
.response(responseBuilder()
.responseCode(String.valueOf(HttpStatus.OK.value()))
.content(contentBuilder()
.mediaType(APPLICATION_JSON_VALUE)
.array(arraySchemaBuilder().schema(
schemaBuilder().implementation(MetaSolverSetting.class)))
)
)
).build();
}

private Mono<ServerResponse> handleMetaSolverSettingsRouteForMetaSolver(
MetaSolver<?, ?, ?> metaSolver) {
return ok().body(Mono.just(metaSolver.getSettings()), new ParameterizedTypeReference<>() {
});
}

private String getRouteForProblemType(ProblemType type) {
return "/meta-solver/settings/" + type.getId();
}
}
Loading