summaryrefslogtreecommitdiff
path: root/opendc-web/opendc-web-server/src/main
diff options
context:
space:
mode:
authormjkwiatkowski <mati.rewa@gmail.com>2026-02-16 15:18:21 +0100
committermjkwiatkowski <mati.rewa@gmail.com>2026-02-16 15:18:21 +0100
commit2f16cb0f48eca4453e3e894b3d45a3aa09e6dcc0 (patch)
tree672d98baa2ac071f2c30de06d613254d0d8cd105 /opendc-web/opendc-web-server/src/main
parent86d35fcec83057e346e4982b5a6908f25342a392 (diff)
feat: opendc -> kafka -> postgresql works; added protobuf encodingHEADmaster
Diffstat (limited to 'opendc-web/opendc-web-server/src/main')
-rw-r--r--opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/model/Job.java166
-rw-r--r--opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/model/Portfolio.java151
-rw-r--r--opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/model/Project.java237
-rw-r--r--opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/model/ProjectAuthorization.java172
-rw-r--r--opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/model/Scenario.java197
-rw-r--r--opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/model/Topology.java153
-rw-r--r--opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/model/Trace.java72
-rw-r--r--opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/model/UserAccounting.java167
-rw-r--r--opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/model/Workload.java61
-rw-r--r--opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/BaseProtocol.java50
-rw-r--r--opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/SchedulerResource.java52
-rw-r--r--opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/TraceResource.java70
-rw-r--r--opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/error/MissingKotlinParameterExceptionMapper.java46
-rw-r--r--opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/error/WebApplicationExceptionMapper.java51
-rw-r--r--opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/runner/JobResource.java110
-rw-r--r--opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/runner/RunnerProtocol.java78
-rw-r--r--opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/user/PortfolioResource.java161
-rw-r--r--opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/user/PortfolioScenarioResource.java159
-rw-r--r--opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/user/ProjectResource.java131
-rw-r--r--opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/user/ScenarioResource.java127
-rw-r--r--opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/user/TopologyResource.java208
-rw-r--r--opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/user/UserProtocol.java132
-rw-r--r--opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/user/UserResource.java73
-rw-r--r--opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/service/JobService.java81
-rw-r--r--opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/service/UserAccountingService.java136
-rw-r--r--opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/util/DevSecurityOverrideFilter.java64
-rw-r--r--opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/util/KotlinModuleCustomizer.java39
-rw-r--r--opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/util/QuarkusObjectMapperSupplier.java39
-rw-r--r--opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/util/runner/QuarkusJobManager.java114
-rw-r--r--opendc-web/opendc-web-server/src/main/resources/META-INF/branding/logo.pngbin2825 -> 0 bytes
-rw-r--r--opendc-web/opendc-web-server/src/main/resources/application-dev.properties36
-rw-r--r--opendc-web/opendc-web-server/src/main/resources/application-docker.properties49
-rw-r--r--opendc-web/opendc-web-server/src/main/resources/application-prod.properties36
-rw-r--r--opendc-web/opendc-web-server/src/main/resources/application-test.properties43
-rw-r--r--opendc-web/opendc-web-server/src/main/resources/application.properties49
-rw-r--r--opendc-web/opendc-web-server/src/main/resources/hypersistence-utils.properties1
-rw-r--r--opendc-web/opendc-web-server/src/main/resources/load_data.sql124
37 files changed, 0 insertions, 3635 deletions
diff --git a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/model/Job.java b/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/model/Job.java
deleted file mode 100644
index a0ac390f..00000000
--- a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/model/Job.java
+++ /dev/null
@@ -1,166 +0,0 @@
-/*
- * Copyright (c) 2022 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.web.server.model;
-
-import io.hypersistence.utils.hibernate.type.json.JsonType;
-import io.quarkus.hibernate.orm.panache.Panache;
-import io.quarkus.hibernate.orm.panache.PanacheEntityBase;
-import io.quarkus.hibernate.orm.panache.PanacheQuery;
-import io.quarkus.panache.common.Parameters;
-import jakarta.persistence.*;
-import java.time.Instant;
-import java.util.Map;
-import org.hibernate.annotations.Type;
-import org.opendc.web.proto.JobState;
-
-/**
- * A simulation job to be run by the simulator.
- */
-@Entity
-@Table
-@NamedQueries({
- @NamedQuery(
- name = "Job.updateOne",
- query =
- """
- UPDATE Job j
- SET j.state = :newState, j.updatedAt = :updatedAt, j.runtime = :runtime, j.results = :results
- WHERE j.id = :id AND j.state = :oldState
- """)
-})
-public class Job extends PanacheEntityBase {
- /**
- * The main ID of a project.
- * The value starts at 6 to account for the other 5 projects already made by the loading script.
- */
- @Id
- @SequenceGenerator(name = "jobSeq", sequenceName = "job_id_seq", allocationSize = 1, initialValue = 3)
- @GeneratedValue(generator = "jobSeq")
- public Long id;
-
- @ManyToOne(optional = false, fetch = FetchType.EAGER)
- @JoinColumn(name = "scenario_id", foreignKey = @ForeignKey(name = "fk_jobs_scenario"), nullable = false)
- public Scenario scenario;
-
- @Column(name = "created_by", nullable = false, updatable = false)
- public String createdBy;
-
- @Column(name = "created_at", nullable = false, updatable = false)
- public Instant createdAt;
-
- /**
- * The number of simulation runs to perform.
- */
- @Column(nullable = false, updatable = false)
- public int repeats;
-
- /**
- * The instant at which the job was updated.
- */
- @Column(name = "updated_at", nullable = false)
- public Instant updatedAt;
-
- /**
- * The state of the job.
- */
- @Enumerated(EnumType.STRING)
- @Column(nullable = false)
- public JobState state = JobState.PENDING;
-
- /**
- * The runtime of the job (in seconds).
- */
- @Column(nullable = false)
- public int runtime = 0;
-
- /**
- * Experiment results in JSON
- */
- @Column(columnDefinition = "jsonb")
- @Type(JsonType.class)
- public Map<String, ?> results = null;
-
- /**
- * Construct a {@link Job} instance.
- */
- public Job(Scenario scenario, String createdBy, Instant createdAt, int repeats) {
- this.createdBy = createdBy;
- this.scenario = scenario;
- this.createdAt = createdAt;
- this.updatedAt = createdAt;
- this.repeats = repeats;
- }
-
- /**
- * JPA constructor
- */
- protected Job() {}
-
- /**
- * Find {@link Job}s in the specified {@link JobState}.
- *
- * @param state The state of the jobs to find.
- * @return A query for jobs that are in the specified state.
- */
- public static PanacheQuery<Job> findByState(JobState state) {
- return find("state", state);
- }
-
- /**
- * Atomically update this job.
- *
- * @param newState The new state to enter into.
- * @param time The time at which the update occurs.
- * @param results The results to possible set.
- * @return <code>true</code> when the update succeeded`, <code>false</code> when there was a conflict.
- */
- public boolean updateAtomically(JobState newState, Instant time, int runtime, Map<String, ?> results) {
- long count = update(
- "#Job.updateOne",
- Parameters.with("id", id)
- .and("oldState", state)
- .and("newState", newState)
- .and("updatedAt", time)
- .and("runtime", runtime)
- .and("results", results));
- Panache.getEntityManager().refresh(this);
- return count > 0;
- }
-
- /**
- * Determine whether the job is allowed to transition to <code>newState</code>.
- *
- * @param newState The new state to transition to.
- * @return <code>true</code> if the transition to the new state is legal, <code>false</code> otherwise.
- */
- public boolean canTransitionTo(JobState newState) {
- // Note that we always allow transitions from the state
- return newState == this.state
- || switch (this.state) {
- case PENDING -> newState == JobState.CLAIMED;
- case CLAIMED -> newState == JobState.RUNNING || newState == JobState.FAILED;
- case RUNNING -> newState == JobState.FINISHED || newState == JobState.FAILED;
- case FINISHED, FAILED -> false;
- };
- }
-}
diff --git a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/model/Portfolio.java b/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/model/Portfolio.java
deleted file mode 100644
index c2695192..00000000
--- a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/model/Portfolio.java
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
- * Copyright (c) 2023 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.web.server.model;
-
-import io.hypersistence.utils.hibernate.type.json.JsonType;
-import io.quarkus.hibernate.orm.panache.PanacheEntityBase;
-import io.quarkus.hibernate.orm.panache.PanacheQuery;
-import io.quarkus.panache.common.Parameters;
-import jakarta.persistence.CascadeType;
-import jakarta.persistence.Column;
-import jakarta.persistence.Entity;
-import jakarta.persistence.GeneratedValue;
-import jakarta.persistence.Id;
-import jakarta.persistence.Index;
-import jakarta.persistence.JoinColumn;
-import jakarta.persistence.ManyToOne;
-import jakarta.persistence.NamedQueries;
-import jakarta.persistence.NamedQuery;
-import jakarta.persistence.OneToMany;
-import jakarta.persistence.OrderBy;
-import jakarta.persistence.SequenceGenerator;
-import jakarta.persistence.Table;
-import jakarta.persistence.UniqueConstraint;
-import java.util.HashSet;
-import java.util.Set;
-import org.hibernate.annotations.Type;
-import org.opendc.web.proto.Targets;
-
-/**
- * A portfolio is the composition of multiple scenarios.
- */
-@Entity
-@Table(
- uniqueConstraints = {
- @UniqueConstraint(
- name = "uk_portfolios_number",
- columnNames = {"project_id", "number"})
- },
- indexes = {@Index(name = "ux_portfolios_number", columnList = "project_id, number")})
-@NamedQueries({
- @NamedQuery(name = "Portfolio.findByProject", query = "SELECT p FROM Portfolio p WHERE p.project.id = :projectId"),
- @NamedQuery(
- name = "Portfolio.findOneByProject",
- query = "SELECT p FROM Portfolio p WHERE p.project.id = :projectId AND p.number = :number")
-})
-public class Portfolio extends PanacheEntityBase {
-
- /**
- * The main ID of a project.
- * The value starts at 6 to account for the other 5 projects already made by the loading script.
- */
- @Id
- @SequenceGenerator(name = "portfolioSeq", sequenceName = "portfolio_id_seq", allocationSize = 1, initialValue = 4)
- @GeneratedValue(generator = "portfolioSeq")
- public Long id;
-
- /**
- * The {@link Project} this portfolio belongs to.
- */
- @ManyToOne(optional = false)
- @JoinColumn(name = "project_id", nullable = false)
- public Project project;
-
- /**
- * Unique number of the portfolio for the project.
- */
- @Column(nullable = false)
- public int number;
-
- /**
- * The name of this portfolio.
- */
- @Column(nullable = false)
- public String name;
-
- /**
- * The portfolio targets (metrics, repetitions).
- */
- @Column(columnDefinition = "jsonb", nullable = false, updatable = false)
- @Type(JsonType.class)
- public Targets targets;
-
- /**
- * The scenarios in this portfolio.
- */
- @OneToMany(
- cascade = {CascadeType.ALL},
- mappedBy = "portfolio",
- orphanRemoval = true)
- @OrderBy("id ASC")
- public Set<Scenario> scenarios = new HashSet<>();
-
- /**
- * Construct a {@link Portfolio} object.
- */
- public Portfolio(Project project, int number, String name, Targets targets) {
- this.project = project;
- this.number = number;
- this.name = name;
- this.targets = targets;
- }
-
- /**
- * JPA constructor
- */
- protected Portfolio() {}
-
- /**
- * Find all {@link Portfolio}s that belong to the specified project
- *
- * @param projectId The unique identifier of the project.
- * @return The query of portfolios that belong to the specified project.
- */
- public static PanacheQuery<Portfolio> findByProject(long projectId) {
- return find("#Portfolio.findByProject", Parameters.with("projectId", projectId));
- }
-
- /**
- * Find the {@link Portfolio} with the specified <code>number</code> belonging to the specified project.
- *
- * @param projectId The unique identifier of the project.
- * @param number The number of the scenario.
- * @return The portfolio or <code>null</code> if it does not exist.
- */
- public static Portfolio findByProject(long projectId, int number) {
- return find(
- "#Portfolio.findOneByProject",
- Parameters.with("projectId", projectId).and("number", number))
- .firstResult();
- }
-}
diff --git a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/model/Project.java b/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/model/Project.java
deleted file mode 100644
index f4e5305d..00000000
--- a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/model/Project.java
+++ /dev/null
@@ -1,237 +0,0 @@
-/*
- * Copyright (c) 2022 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.web.server.model;
-
-import io.quarkus.hibernate.orm.panache.Panache;
-import io.quarkus.hibernate.orm.panache.PanacheEntityBase;
-import io.quarkus.panache.common.Parameters;
-import jakarta.persistence.CascadeType;
-import jakarta.persistence.Column;
-import jakarta.persistence.Entity;
-import jakarta.persistence.GeneratedValue;
-import jakarta.persistence.Id;
-import jakarta.persistence.NamedQueries;
-import jakarta.persistence.NamedQuery;
-import jakarta.persistence.OneToMany;
-import jakarta.persistence.OrderBy;
-import jakarta.persistence.SequenceGenerator;
-import jakarta.persistence.Table;
-import java.time.Instant;
-import java.util.HashSet;
-import java.util.Set;
-
-/**
- * A project in OpenDC encapsulates all the datacenter designs and simulation runs for a set of users.
- */
-@Entity
-@Table
-@NamedQueries({
- @NamedQuery(
- name = "Project.findByUser",
- query =
- """
- SELECT a
- FROM ProjectAuthorization a
- WHERE a.key.userName = :userName
- """),
- @NamedQuery(
- name = "Project.allocatePortfolio",
- query =
- """
- UPDATE Project p
- SET p.portfoliosCreated = :oldState + 1, p.updatedAt = :now
- WHERE p.id = :id AND p.portfoliosCreated = :oldState
- """),
- @NamedQuery(
- name = "Project.allocateTopology",
- query =
- """
- UPDATE Project p
- SET p.topologiesCreated = :oldState + 1, p.updatedAt = :now
- WHERE p.id = :id AND p.topologiesCreated = :oldState
- """),
- @NamedQuery(
- name = "Project.allocateScenario",
- query =
- """
- UPDATE Project p
- SET p.scenariosCreated = :oldState + 1, p.updatedAt = :now
- WHERE p.id = :id AND p.scenariosCreated = :oldState
- """)
-})
-public class Project extends PanacheEntityBase {
-
- /**
- * The main ID of a project.
- * The value starts at 6 to account for the other 5 projects already made by the loading script.
- */
- @Id
- @SequenceGenerator(name = "projectSeq", sequenceName = "project_id_seq", allocationSize = 1, initialValue = 7)
- @GeneratedValue(generator = "projectSeq")
- public Long id;
-
- /**
- * The name of the project.
- */
- @Column(nullable = false)
- public String name;
-
- /**
- * The instant at which the project was created.
- */
- @Column(name = "created_at", nullable = false, updatable = false)
- public Instant createdAt;
-
- /**
- * The instant at which the project was updated.
- */
- @Column(name = "updated_at", nullable = false)
- public Instant updatedAt;
-
- /**
- * The portfolios belonging to this project.
- */
- @OneToMany(
- cascade = {CascadeType.ALL},
- mappedBy = "project",
- orphanRemoval = true)
- @OrderBy("id ASC")
- public Set<Portfolio> portfolios = new HashSet<>();
-
- /**
- * The number of portfolios created for this project (including deleted portfolios).
- */
- @Column(name = "portfolios_created", nullable = false)
- public int portfoliosCreated = 0;
-
- /**
- * The topologies belonging to this project.
- */
- @OneToMany(
- cascade = {CascadeType.ALL},
- mappedBy = "project",
- orphanRemoval = true)
- @OrderBy("id ASC")
- public Set<Topology> topologies = new HashSet<>();
-
- /**
- * The number of topologies created for this project (including deleted topologies).
- */
- @Column(name = "topologies_created", nullable = false)
- public int topologiesCreated = 0;
-
- /**
- * The scenarios belonging to this project.
- */
- @OneToMany(mappedBy = "project", orphanRemoval = true)
- public Set<Scenario> scenarios = new HashSet<>();
-
- /**
- * The number of scenarios created for this project (including deleted scenarios).
- */
- @Column(name = "scenarios_created", nullable = false)
- public int scenariosCreated = 0;
-
- /**
- * The users authorized to access the project.
- */
- @OneToMany(
- cascade = {CascadeType.ALL},
- mappedBy = "project",
- orphanRemoval = true)
- public Set<ProjectAuthorization> authorizations = new HashSet<>();
-
- /**
- * Construct a {@link Project} object.
- */
- public Project(String name, Instant createdAt) {
- this.name = name;
- this.createdAt = createdAt;
- this.updatedAt = createdAt;
- }
-
- /**
- * JPA constructor
- */
- protected Project() {}
-
- /**
- * Allocate the next portfolio number for the specified [project].
- *
- * @param time The time at which the new portfolio is created.
- */
- public int allocatePortfolio(Instant time) {
- for (int i = 0; i < 4; i++) {
- long count = update(
- "#Project.allocatePortfolio",
- Parameters.with("id", id).and("oldState", portfoliosCreated).and("now", time));
- if (count > 0) {
- return portfoliosCreated + 1;
- } else {
- Panache.getEntityManager().refresh(this);
- }
- }
-
- throw new IllegalStateException("Failed to allocate next portfolio");
- }
-
- /**
- * Allocate the next topology number for the specified [project].
- *
- * @param time The time at which the new topology is created.
- */
- public int allocateTopology(Instant time) {
- for (int i = 0; i < 4; i++) {
- long count = update(
- "#Project.allocateTopology",
- Parameters.with("id", id).and("oldState", topologiesCreated).and("now", time));
- if (count > 0) {
- return topologiesCreated + 1;
- } else {
- Panache.getEntityManager().refresh(this);
- }
- }
-
- throw new IllegalStateException("Failed to allocate next topology");
- }
-
- /**
- * Allocate the next scenario number for the specified [project].
- *
- * @param time The time at which the new scenario is created.
- */
- public int allocateScenario(Instant time) {
- for (int i = 0; i < 4; i++) {
- long count = update(
- "#Project.allocateScenario",
- Parameters.with("id", id).and("oldState", scenariosCreated).and("now", time));
- if (count > 0) {
- return scenariosCreated + 1;
- } else {
- Panache.getEntityManager().refresh(this);
- }
- }
-
- throw new IllegalStateException("Failed to allocate next scenario");
- }
-}
diff --git a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/model/ProjectAuthorization.java b/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/model/ProjectAuthorization.java
deleted file mode 100644
index 3776ae12..00000000
--- a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/model/ProjectAuthorization.java
+++ /dev/null
@@ -1,172 +0,0 @@
-/*
- * Copyright (c) 2022 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.web.server.model;
-
-import io.quarkus.hibernate.orm.panache.PanacheEntityBase;
-import io.quarkus.hibernate.orm.panache.PanacheQuery;
-import io.quarkus.panache.common.Parameters;
-import jakarta.persistence.Column;
-import jakarta.persistence.Embeddable;
-import jakarta.persistence.EmbeddedId;
-import jakarta.persistence.Entity;
-import jakarta.persistence.EnumType;
-import jakarta.persistence.Enumerated;
-import jakarta.persistence.FetchType;
-import jakarta.persistence.ForeignKey;
-import jakarta.persistence.JoinColumn;
-import jakarta.persistence.ManyToOne;
-import jakarta.persistence.MapsId;
-import jakarta.persistence.NamedQueries;
-import jakarta.persistence.NamedQuery;
-import jakarta.persistence.Table;
-import java.io.Serializable;
-import java.util.Objects;
-import org.opendc.web.proto.user.ProjectRole;
-
-/**
- * An authorization for some user to participate in a project.
- */
-@Entity
-@Table
-@NamedQueries({
- @NamedQuery(
- name = "ProjectAuthorization.findByUser",
- query =
- """
- SELECT a
- FROM ProjectAuthorization a
- WHERE a.key.userName = :userName
- """),
-})
-public class ProjectAuthorization extends PanacheEntityBase {
- /**
- * The user identifier of the authorization.
- */
- @EmbeddedId
- public ProjectAuthorization.Key key;
-
- /**
- * The project that the user is authorized to participate in.
- */
- @ManyToOne(optional = false, fetch = FetchType.LAZY)
- @MapsId("projectId")
- @JoinColumn(
- name = "project_id",
- updatable = false,
- insertable = false,
- nullable = false,
- foreignKey = @ForeignKey(name = "fk_project_authorizations"))
- public Project project;
-
- /**
- * The role of the user in the project.
- */
- @Column(nullable = false)
- @Enumerated(EnumType.STRING)
- public ProjectRole role;
-
- /**
- * Construct a {@link ProjectAuthorization} object.
- */
- public ProjectAuthorization(Project project, String userName, ProjectRole role) {
- this.key = new ProjectAuthorization.Key(project.id, userName);
- this.project = project;
- this.role = role;
- }
-
- /**
- * JPA constructor
- */
- protected ProjectAuthorization() {}
-
- /**
- * List all projects for the user with the specified <code>userName</code>.
- *
- * @param userName The identifier of the user that is requesting the list of projects.
- * @return A query returning projects that the user has received authorization for.
- */
- public static PanacheQuery<ProjectAuthorization> findByUser(String userName) {
- return find("#ProjectAuthorization.findByUser", Parameters.with("userName", userName));
- }
-
- /**
- * Find the project with <code>id</code> for the user with the specified <code>userName</code>.
- *
- * @param userName The identifier of the user that is requesting the list of projects.
- * @param project_id The unique identifier of the project.
- * @return The project with the specified identifier or <code>null</code> if it does not exist or is not accessible
- * to the user with the specified identifier.
- */
- public static ProjectAuthorization findByUser(String userName, long project_id) {
- return findById(new ProjectAuthorization.Key(project_id, userName));
- }
-
- /**
- * Determine whether the authorization allows the user to edit the project.
- */
- public boolean canEdit() {
- return switch (role) {
- case OWNER, EDITOR -> true;
- case VIEWER -> false;
- };
- }
-
- /**
- * Determine whether the authorization allows the user to delete the project.
- */
- public boolean canDelete() {
- return role == ProjectRole.OWNER;
- }
-
- /**
- * Key for representing a {@link ProjectAuthorization} object.
- */
- @Embeddable
- public static class Key implements Serializable {
- @Column(name = "project_id", nullable = false)
- public long projectId;
-
- @Column(name = "user_name", nullable = false)
- public String userName;
-
- public Key(long projectId, String userName) {
- this.projectId = projectId;
- this.userName = userName;
- }
-
- protected Key() {}
-
- @Override
- public boolean equals(Object o) {
- if (this == o) return true;
- if (o == null || getClass() != o.getClass()) return false;
- Key key = (Key) o;
- return projectId == key.projectId && userName.equals(key.userName);
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(projectId, userName);
- }
- }
-}
diff --git a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/model/Scenario.java b/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/model/Scenario.java
deleted file mode 100644
index c79ef5bb..00000000
--- a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/model/Scenario.java
+++ /dev/null
@@ -1,197 +0,0 @@
-/*
- * Copyright (c) 2023 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.web.server.model;
-
-import io.hypersistence.utils.hibernate.type.json.JsonType;
-import io.quarkus.hibernate.orm.panache.PanacheEntityBase;
-import io.quarkus.hibernate.orm.panache.PanacheQuery;
-import io.quarkus.panache.common.Parameters;
-import jakarta.persistence.*;
-import java.util.ArrayList;
-import java.util.List;
-import org.hibernate.annotations.Type;
-import org.opendc.web.proto.OperationalPhenomena;
-
-/**
- * A single scenario to be explored by the simulator.
- */
-@Entity
-@Table(
- uniqueConstraints = {
- @UniqueConstraint(
- name = "uk_scenarios_number",
- columnNames = {"project_id", "number"})
- },
- indexes = {@Index(name = "ux_scenarios_number", columnList = "project_id, number")})
-@NamedQueries({
- @NamedQuery(name = "Scenario.findByProject", query = "SELECT s FROM Scenario s WHERE s.project.id = :projectId"),
- @NamedQuery(
- name = "Scenario.findByPortfolio",
- query =
- """
- SELECT s
- FROM Scenario s
- JOIN Portfolio p ON p.id = s.portfolio.id AND p.number = :number
- WHERE s.project.id = :projectId
- """),
- @NamedQuery(
- name = "Scenario.findOneByProject",
- query = "SELECT s FROM Scenario s WHERE s.project.id = :projectId AND s.number = :number")
-})
-public class Scenario extends PanacheEntityBase {
- /**
- * The main ID of a Scenario.
- * The value starts at 3 to account for the other 2 scenarios already made by the loading script.
- */
- @Id
- @SequenceGenerator(name = "scenarioSeq", sequenceName = "scenario_id_seq", allocationSize = 1, initialValue = 3)
- @GeneratedValue(generator = "scenarioSeq")
- public Long id;
-
- /**
- * The {@link Project} to which this scenario belongs.
- */
- @ManyToOne(optional = false)
- @JoinColumn(name = "project_id", nullable = false, foreignKey = @ForeignKey(name = "fk_scenarios_project"))
- public Project project;
-
- /**
- * The {@link Portfolio} to which this scenario belongs.
- */
- @ManyToOne(optional = false)
- @JoinColumn(name = "portfolio_id", nullable = false, foreignKey = @ForeignKey(name = "fk_scenarios_portfolio"))
- public Portfolio portfolio;
-
- /**
- * Unique number of the scenario for the project.
- */
- @Column(nullable = false)
- public int number;
-
- /**
- * The name of the scenario.
- */
- @Column(nullable = false, updatable = false)
- public String name;
-
- /**
- * Workload details of the scenario.
- */
- @Embedded
- public Workload workload;
-
- /**
- * Topology details of the scenario.
- */
- @ManyToOne(optional = false)
- @JoinColumn(name = "topology_id", nullable = false, foreignKey = @ForeignKey(name = "fk_scenarios_topology"))
- public Topology topology;
-
- /**
- * Operational phenomena activated in the scenario.
- * @Column(columnDefinition = "jsonb", nullable = false, updatable = false)
- * @Type(JsonType.class)
- */
- @Column(columnDefinition = "jsonb", nullable = false, updatable = false)
- @Type(JsonType.class)
- public OperationalPhenomena phenomena;
-
- /**
- * The name of the VM scheduler used in the scenario.
- */
- @Column(name = "scheduler_name", nullable = false, updatable = false)
- public String schedulerName;
-
- /**
- * The {@link Job} associated with the scenario.
- */
- @OneToMany(
- cascade = {CascadeType.ALL},
- mappedBy = "scenario",
- fetch = FetchType.LAZY)
- public List<Job> jobs = new ArrayList<>();
-
- /**
- * Construct a {@link Scenario} object.
- */
- public Scenario(
- Project project,
- Portfolio portfolio,
- int number,
- String name,
- Workload workload,
- Topology topology,
- OperationalPhenomena phenomena,
- String schedulerName) {
- this.project = project;
- this.portfolio = portfolio;
- this.number = number;
- this.name = name;
- this.workload = workload;
- this.topology = topology;
- this.phenomena = phenomena;
- this.schedulerName = schedulerName;
- }
-
- /**
- * JPA constructor
- */
- protected Scenario() {}
-
- /**
- * Find all {@link Scenario}s that belong to the specified project
- *
- * @param projectId The unique identifier of the project.
- * @return The query of scenarios that belong to the specified project.
- */
- public static PanacheQuery<Scenario> findByProject(long projectId) {
- return find("#Scenario.findByProject", Parameters.with("projectId", projectId));
- }
-
- /**
- * Find all {@link Scenario}s that belong to the specified portfolio.
- *
- * @param projectId The unique identifier of the project.
- * @param number The number of the portfolio.
- * @return The query of scenarios that belong to the specified project and portfolio..
- */
- public static PanacheQuery<Scenario> findByPortfolio(long projectId, int number) {
- return find(
- "#Scenario.findByPortfolio",
- Parameters.with("projectId", projectId).and("number", number));
- }
-
- /**
- * Find the {@link Scenario} with the specified <code>number</code> belonging to the specified project.
- *
- * @param projectId The unique identifier of the project.
- * @param number The number of the scenario.
- * @return The scenario or <code>null</code> if it does not exist.
- */
- public static Scenario findByProject(long projectId, int number) {
- return find(
- "#Scenario.findOneByProject",
- Parameters.with("projectId", projectId).and("number", number))
- .firstResult();
- }
-}
diff --git a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/model/Topology.java b/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/model/Topology.java
deleted file mode 100644
index 8a4e2ae2..00000000
--- a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/model/Topology.java
+++ /dev/null
@@ -1,153 +0,0 @@
-/*
- * Copyright (c) 2022 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.web.server.model;
-
-import io.hypersistence.utils.hibernate.type.json.JsonType;
-import io.quarkus.hibernate.orm.panache.PanacheEntityBase;
-import io.quarkus.hibernate.orm.panache.PanacheQuery;
-import io.quarkus.panache.common.Parameters;
-import jakarta.persistence.Column;
-import jakarta.persistence.Entity;
-import jakarta.persistence.GeneratedValue;
-import jakarta.persistence.Id;
-import jakarta.persistence.Index;
-import jakarta.persistence.JoinColumn;
-import jakarta.persistence.ManyToOne;
-import jakarta.persistence.NamedQueries;
-import jakarta.persistence.NamedQuery;
-import jakarta.persistence.SequenceGenerator;
-import jakarta.persistence.Table;
-import jakarta.persistence.UniqueConstraint;
-import java.time.Instant;
-import java.util.List;
-import org.hibernate.annotations.Type;
-import org.opendc.web.proto.Room;
-
-/**
- * A datacenter design in OpenDC.
- */
-@Entity
-@Table(
- uniqueConstraints = {
- @UniqueConstraint(
- name = "uk_topologies_number",
- columnNames = {"project_id", "number"})
- },
- indexes = {@Index(name = "ux_topologies_number", columnList = "project_id, number")})
-@NamedQueries({
- @NamedQuery(name = "Topology.findByProject", query = "SELECT t FROM Topology t WHERE t.project.id = :projectId"),
- @NamedQuery(
- name = "Topology.findOneByProject",
- query = "SELECT t FROM Topology t WHERE t.project.id = :projectId AND t.number = :number")
-})
-public class Topology extends PanacheEntityBase {
- /**
- * The main ID of a project.
- * The value starts at 6 to account for the other 5 projects already made by the loading script.
- */
- @Id
- @SequenceGenerator(name = "topologySeq", sequenceName = "topology_id_seq", allocationSize = 1, initialValue = 5)
- @GeneratedValue(generator = "topologySeq")
- public Long id;
-
- /**
- * The {@link Project} to which the topology belongs.
- */
- @ManyToOne(optional = false)
- @JoinColumn(name = "project_id", nullable = false)
- public Project project;
-
- /**
- * Unique number of the topology for the project.
- */
- @Column(nullable = false)
- public int number;
-
- /**
- * The name of the topology.
- */
- @Column(nullable = false)
- public String name;
-
- /**
- * The instant at which the topology was created.
- */
- @Column(name = "created_at", nullable = false, updatable = false)
- public Instant createdAt;
-
- /**
- * The instant at which the topology was updated.
- */
- @Column(name = "updated_at", nullable = false)
- public Instant updatedAt;
-
- /**
- * Datacenter design in JSON
- * @Column(columnDefinition = "jsonb", nullable = false)
- * @Type(JsonType.class)
- */
- @Column(columnDefinition = "jsonb", nullable = false)
- @Type(JsonType.class)
- public List<Room> rooms;
-
- /**
- * Construct a {@link Topology} object.
- */
- public Topology(Project project, int number, String name, Instant createdAt, List<Room> rooms) {
- this.project = project;
- this.number = number;
- this.name = name;
- this.createdAt = createdAt;
- this.updatedAt = createdAt;
- this.rooms = rooms;
- }
-
- /**
- * JPA constructor
- */
- protected Topology() {}
-
- /**
- * Find all [Topology]s that belong to [project][projectId].
- *
- * @param projectId The unique identifier of the project.
- * @return The query of topologies that belong to the specified project.
- */
- public static PanacheQuery<Topology> findByProject(long projectId) {
- return find("#Topology.findByProject", Parameters.with("projectId", projectId));
- }
-
- /**
- * Find the [Topology] with the specified [number] belonging to [project][projectId].
- *
- * @param projectId The unique identifier of the project.
- * @param number The number of the topology.
- * @return The topology or `null` if it does not exist.
- */
- public static Topology findByProject(long projectId, int number) {
- return find(
- "#Topology.findOneByProject",
- Parameters.with("projectId", projectId).and("number", number))
- .firstResult();
- }
-}
diff --git a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/model/Trace.java b/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/model/Trace.java
deleted file mode 100644
index 71c647bc..00000000
--- a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/model/Trace.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright (c) 2021 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.web.server.model;
-
-import io.quarkus.hibernate.orm.panache.PanacheEntityBase;
-import jakarta.persistence.Column;
-import jakarta.persistence.Entity;
-import jakarta.persistence.Id;
-import jakarta.persistence.Table;
-
-/**
- * A workload trace available for simulation.
- */
-@Entity
-@Table
-public class Trace extends PanacheEntityBase {
- /**
- * The unique identifier of the trace.
- */
- @Id
- public String id;
-
- /**
- * The name of the trace.
- */
- @Column(nullable = false, updatable = false)
- public String name;
-
- /**
- * The type of trace.
- */
- @Column(nullable = false, updatable = false)
- public String type;
-
- /**
- * Construct a {@link Trace}.
- *
- * @param id The unique identifier of the trace.
- * @param name The name of the trace.
- * @param type The type of trace.
- */
- public Trace(String id, String name, String type) {
- this.id = id;
- this.name = name;
- this.type = type;
- }
-
- /**
- * JPA constructor.
- */
- protected Trace() {}
-}
diff --git a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/model/UserAccounting.java b/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/model/UserAccounting.java
deleted file mode 100644
index 10a10ef9..00000000
--- a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/model/UserAccounting.java
+++ /dev/null
@@ -1,167 +0,0 @@
-/*
- * Copyright (c) 2023 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.web.server.model;
-
-import io.quarkus.hibernate.orm.panache.PanacheEntityBase;
-import io.quarkus.panache.common.Parameters;
-import jakarta.persistence.Column;
-import jakarta.persistence.Entity;
-import jakarta.persistence.Id;
-import jakarta.persistence.NamedQueries;
-import jakarta.persistence.NamedQuery;
-import jakarta.persistence.Table;
-import java.time.LocalDate;
-
-/**
- * Entity to track the number of simulation minutes used by a user.
- */
-@Entity
-@Table
-@NamedQueries({
- @NamedQuery(
- name = "UserAccounting.consumeBudget",
- query =
- """
- UPDATE UserAccounting a
- SET a.simulationTime = a.simulationTime + :seconds
- WHERE a.userId = :userId AND a.periodEnd = :periodEnd
- """),
- @NamedQuery(
- name = "UserAccounting.resetBudget",
- query =
- """
- UPDATE UserAccounting a
- SET a.periodEnd = :periodEnd, a.simulationTime = :seconds
- WHERE a.userId = :userId AND a.periodEnd = :oldPeriodEnd
- """)
-})
-public class UserAccounting extends PanacheEntityBase {
- /**
- * User to which this object belongs.
- */
- @Id
- @Column(name = "user_id", nullable = false)
- public String userId;
-
- /**
- * The end of the accounting period.
- */
- @Column(name = "period_end", nullable = false)
- public LocalDate periodEnd;
-
- /**
- * The number of simulation seconds to be used per accounting period.
- */
- @Column(name = "simulation_time_budget", nullable = false)
- public int simulationTimeBudget;
-
- /**
- * The number of simulation seconds used in this period. This number should reset once the accounting period has
- * been reached.
- */
- @Column(name = "simulation_time", nullable = false)
- public int simulationTime = 0;
-
- /**
- * Construct a new {@link UserAccounting} object.
- *
- * @param userId The identifier of the user that this object belongs to.
- * @param periodEnd The end of the accounting period.
- * @param simulationTimeBudget The number of simulation seconds available per accounting period.
- */
- public UserAccounting(String userId, LocalDate periodEnd, int simulationTimeBudget) {
- this.userId = userId;
- this.periodEnd = periodEnd;
- this.simulationTimeBudget = simulationTimeBudget;
- }
-
- /**
- * JPA constructor.
- */
- protected UserAccounting() {}
-
- /**
- * Return the {@link UserAccounting} object associated with the specified user id.
- */
- public static UserAccounting findByUser(String userId) {
- return findById(userId);
- }
-
- /**
- * Create a new {@link UserAccounting} object and persist it to the database.
- *
- * @param userId The identifier of the user that this object belongs to.
- * @param periodEnd The end of the accounting period.
- * @param simulationTimeBudget The number of simulation seconds available per accounting period.
- * @param simulationTime The initial simulation time that has been consumed.
- */
- public static UserAccounting create(
- String userId, LocalDate periodEnd, int simulationTimeBudget, int simulationTime) {
- UserAccounting newAccounting = new UserAccounting(userId, periodEnd, simulationTimeBudget);
- newAccounting.simulationTime = simulationTime;
- newAccounting.persistAndFlush();
- return newAccounting;
- }
-
- /**
- * Atomically consume the budget for this {@link UserAccounting} object.
- *
- * @param seconds The number of seconds to consume from the user.
- * @return <code>true</code> when the update succeeded, <code>false</code> when there was a conflict.
- */
- public boolean consumeBudget(int seconds) {
- long count = update(
- "#UserAccounting.consumeBudget",
- Parameters.with("userId", userId).and("periodEnd", periodEnd).and("seconds", seconds));
- return count > 0;
- }
-
- /**
- * Atomically reset the budget for this {@link UserAccounting} object.
- *
- * @param periodEnd The new end period for the budget.
- * @param seconds The number of seconds that have already been consumed.
- * @return <code>true</code> when the update succeeded`, <code>false</code> when there was a conflict.
- */
- public boolean resetBudget(LocalDate periodEnd, int seconds) {
- long count = update(
- "#UserAccounting.resetBudget",
- Parameters.with("userId", userId)
- .and("oldPeriodEnd", this.periodEnd)
- .and("periodEnd", periodEnd)
- .and("seconds", seconds));
- return count > 0;
- }
-
- /**
- * Determine whether the user has any remaining simulation budget.
- *
- * @return <code>true</code> when the user still has budget left, <code>false</code> otherwise.
- */
- public boolean hasSimulationBudget() {
- var today = LocalDate.now();
-
- // The accounting period must be over or there must be budget remaining.
- return !today.isBefore(periodEnd) || simulationTimeBudget > simulationTime;
- }
-}
diff --git a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/model/Workload.java b/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/model/Workload.java
deleted file mode 100644
index fd7010d2..00000000
--- a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/model/Workload.java
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright (c) 2023 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.web.server.model;
-
-import jakarta.persistence.Column;
-import jakarta.persistence.Embeddable;
-import jakarta.persistence.ManyToOne;
-
-/**
- * Specification of the workload for a {@link Scenario}
- */
-@Embeddable
-public class Workload {
- /**
- * The {@link Trace} that the workload runs.
- */
- @ManyToOne(optional = false)
- public Trace trace;
-
- /**
- * The percentage of the trace that should be sampled.
- */
- @Column(name = "sampling_fraction", nullable = false, updatable = false)
- public double samplingFraction;
-
- /**
- * Construct a {@link Workload} object.
- *
- * @param trace The {@link Trace} to run as workload.
- * @param samplingFraction The percentage of the workload to sample.
- */
- public Workload(Trace trace, double samplingFraction) {
- this.trace = trace;
- this.samplingFraction = samplingFraction;
- }
-
- /**
- * JPA constructor.
- */
- protected Workload() {}
-}
diff --git a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/BaseProtocol.java b/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/BaseProtocol.java
deleted file mode 100644
index 44d2d569..00000000
--- a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/BaseProtocol.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright (c) 2023 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.web.server.rest;
-
-import org.opendc.web.server.model.Trace;
-import org.opendc.web.server.model.Workload;
-
-/**
- * DTO-conversions for the base protocol.
- */
-public final class BaseProtocol {
- /**
- * Private constructor to prevent instantiation of class.
- */
- private BaseProtocol() {}
-
- /**
- * Convert a {@link Workload} entity into a DTO.
- */
- public static org.opendc.web.proto.Workload toDto(Workload workload) {
- return new org.opendc.web.proto.Workload(toDto(workload.trace), workload.samplingFraction);
- }
-
- /**
- * Convert a {@link Trace] entity into a {@link org.opendc.web.proto.Trace} DTO.
- */
- public static org.opendc.web.proto.Trace toDto(Trace trace) {
- return new org.opendc.web.proto.Trace(trace.id, trace.name, trace.type);
- }
-}
diff --git a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/SchedulerResource.java b/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/SchedulerResource.java
deleted file mode 100644
index 3e839040..00000000
--- a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/SchedulerResource.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (c) 2023 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.web.server.rest;
-
-import jakarta.ws.rs.GET;
-import jakarta.ws.rs.Path;
-import jakarta.ws.rs.Produces;
-import java.util.List;
-
-/**
- * A resource representing the available schedulers that can be used during experiments.
- */
-@Produces("application/json")
-@Path("/schedulers")
-public final class SchedulerResource {
- /**
- * Obtain all available schedulers.
- */
- @GET
- public List<String> getAll() {
- return List.of(
- "mem",
- "mem-inv",
- "core-mem",
- "core-mem-inv",
- "active-tasks",
- "active-tasks-inv",
- "provisioned-cores",
- "provisioned-cores-inv",
- "random");
- }
-}
diff --git a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/TraceResource.java b/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/TraceResource.java
deleted file mode 100644
index daec01cd..00000000
--- a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/TraceResource.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright (c) 2023 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.web.server.rest;
-
-import jakarta.ws.rs.GET;
-import jakarta.ws.rs.Path;
-import jakarta.ws.rs.PathParam;
-import jakarta.ws.rs.Produces;
-import jakarta.ws.rs.WebApplicationException;
-import java.util.List;
-import java.util.stream.Stream;
-import org.opendc.web.server.model.Trace;
-
-/**
- * A resource representing the workload traces available in the OpenDC instance.
- */
-@Produces("application/json")
-@Path("/traces")
-public final class TraceResource {
- /**
- * Obtain all available traces.
- */
- @GET
- public List<org.opendc.web.proto.Trace> getAll() {
- Stream<Trace> entities = Trace.streamAll();
- return entities.map(TraceResource::toDto).toList();
- }
-
- /**
- * Obtain trace information by identifier.
- */
- @GET
- @Path("{id}")
- public org.opendc.web.proto.Trace get(@PathParam("id") String id) {
- Trace trace = Trace.findById(id);
-
- if (trace == null) {
- throw new WebApplicationException("Trace not found", 404);
- }
-
- return toDto(trace);
- }
-
- /**
- * Convert a {@link Trace] entity into a {@link org.opendc.web.proto.Trace} DTO.
- */
- public static org.opendc.web.proto.Trace toDto(Trace trace) {
- return new org.opendc.web.proto.Trace(trace.id, trace.name, trace.type);
- }
-}
diff --git a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/error/MissingKotlinParameterExceptionMapper.java b/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/error/MissingKotlinParameterExceptionMapper.java
deleted file mode 100644
index 345acdfe..00000000
--- a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/error/MissingKotlinParameterExceptionMapper.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright (c) 2023 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.web.server.rest.error;
-
-import com.fasterxml.jackson.module.kotlin.MissingKotlinParameterException;
-import jakarta.ws.rs.core.MediaType;
-import jakarta.ws.rs.core.Response;
-import jakarta.ws.rs.ext.ExceptionMapper;
-import jakarta.ws.rs.ext.Provider;
-import org.opendc.web.proto.ProtocolError;
-
-/**
- * An [ExceptionMapper] for [MissingKotlinParameterException] thrown by Jackson.
- */
-@Provider
-public final class MissingKotlinParameterExceptionMapper implements ExceptionMapper<MissingKotlinParameterException> {
- @Override
- public Response toResponse(MissingKotlinParameterException exception) {
- return Response.status(Response.Status.BAD_REQUEST)
- .entity(new ProtocolError(
- Response.Status.BAD_REQUEST.getStatusCode(),
- "Field " + exception.getParameter().getName() + " is missing from body."))
- .type(MediaType.APPLICATION_JSON)
- .build();
- }
-}
diff --git a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/error/WebApplicationExceptionMapper.java b/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/error/WebApplicationExceptionMapper.java
deleted file mode 100644
index e027e559..00000000
--- a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/error/WebApplicationExceptionMapper.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright (c) 2023 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.web.server.rest.error;
-
-import jakarta.ws.rs.WebApplicationException;
-import jakarta.ws.rs.core.MediaType;
-import jakarta.ws.rs.core.Response;
-import jakarta.ws.rs.ext.ExceptionMapper;
-import jakarta.ws.rs.ext.Provider;
-import org.opendc.web.proto.ProtocolError;
-
-/**
- * Helper class to transform a {@link WebApplicationException} into an JSON error response.
- */
-@Provider
-public final class WebApplicationExceptionMapper implements ExceptionMapper<WebApplicationException> {
- @Override
- public Response toResponse(WebApplicationException exception) {
- int code = exception.getResponse().getStatus();
-
- String message = exception.getMessage();
- if (message == null) {
- message = "Unknown error";
- }
-
- return Response.status(code)
- .entity(new ProtocolError(code, message))
- .type(MediaType.APPLICATION_JSON)
- .build();
- }
-}
diff --git a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/runner/JobResource.java b/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/runner/JobResource.java
deleted file mode 100644
index 4dde8654..00000000
--- a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/runner/JobResource.java
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * Copyright (c) 2023 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.web.server.rest.runner;
-
-import jakarta.annotation.security.RolesAllowed;
-import jakarta.transaction.Transactional;
-import jakarta.validation.Valid;
-import jakarta.ws.rs.Consumes;
-import jakarta.ws.rs.GET;
-import jakarta.ws.rs.POST;
-import jakarta.ws.rs.Path;
-import jakarta.ws.rs.PathParam;
-import jakarta.ws.rs.Produces;
-import jakarta.ws.rs.WebApplicationException;
-import java.util.List;
-import org.opendc.web.proto.JobState;
-import org.opendc.web.server.model.Job;
-import org.opendc.web.server.service.JobService;
-
-/**
- * A resource representing the available simulation jobs.
- */
-@Produces("application/json")
-@Path("/jobs")
-@RolesAllowed("runner")
-public final class JobResource {
- /**
- * The {@link JobService} for helping manage the job lifecycle.
- */
- private final JobService jobService;
-
- /**
- * Construct a {@link JobResource} instance.
- *
- * @param jobService The {@link JobService} for managing the job lifecycle.
- */
- public JobResource(JobService jobService) {
- this.jobService = jobService;
- }
-
- /**
- * Obtain all pending simulation jobs.
- */
- @GET
- public List<org.opendc.web.proto.runner.Job> queryPending() {
- return Job.findByState(JobState.PENDING).list().stream()
- .map(RunnerProtocol::toDto)
- .toList();
- }
-
- /**
- * Get a job by identifier.
- */
- @GET
- @Path("{job}")
- public org.opendc.web.proto.runner.Job get(@PathParam("job") long id) {
- Job job = Job.findById(id);
-
- if (job == null) {
- throw new WebApplicationException("Job not found", 404);
- }
-
- return RunnerProtocol.toDto(job);
- }
-
- /**
- * Atomically update the state of a job.
- */
- @POST
- @Path("{job}")
- @Consumes("application/json")
- @Transactional
- public org.opendc.web.proto.runner.Job update(
- @PathParam("job") long id, @Valid org.opendc.web.proto.runner.Job.Update update) {
- Job job = Job.findById(id);
- if (job == null) {
- throw new WebApplicationException("Job not found", 404);
- }
-
- try {
- jobService.updateJob(job, update.getState(), update.getRuntime(), update.getResults());
- } catch (IllegalArgumentException e) {
- throw new WebApplicationException(e, 400);
- } catch (IllegalStateException e) {
- throw new WebApplicationException(e, 409);
- }
-
- return RunnerProtocol.toDto(job);
- }
-}
diff --git a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/runner/RunnerProtocol.java b/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/runner/RunnerProtocol.java
deleted file mode 100644
index 6bf65d97..00000000
--- a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/runner/RunnerProtocol.java
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Copyright (c) 2023 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.web.server.rest.runner;
-
-import org.opendc.web.server.model.Job;
-import org.opendc.web.server.model.Portfolio;
-import org.opendc.web.server.model.Scenario;
-import org.opendc.web.server.model.Topology;
-import org.opendc.web.server.rest.BaseProtocol;
-
-/**
- * DTO-conversions for the runner protocol.
- */
-public final class RunnerProtocol {
- /**
- * Private constructor to prevent instantiation of class.
- */
- private RunnerProtocol() {}
-
- /**
- * Convert a {@link Job} into a runner-facing DTO.
- */
- public static org.opendc.web.proto.runner.Job toDto(Job job) {
- return new org.opendc.web.proto.runner.Job(
- job.id, toDto(job.scenario), job.state, job.createdAt, job.updatedAt, job.runtime, job.results);
- }
-
- /**
- * Convert a {@link Scenario} into a runner-facing DTO.
- */
- public static org.opendc.web.proto.runner.Scenario toDto(Scenario scenario) {
- return new org.opendc.web.proto.runner.Scenario(
- scenario.id,
- scenario.number,
- toDto(scenario.portfolio),
- scenario.name,
- BaseProtocol.toDto(scenario.workload),
- toDto(scenario.topology),
- scenario.phenomena,
- scenario.schedulerName);
- }
-
- /**
- * Convert a {@link Portfolio} into a runner-facing DTO.
- */
- public static org.opendc.web.proto.runner.Portfolio toDto(Portfolio portfolio) {
- return new org.opendc.web.proto.runner.Portfolio(
- portfolio.id, portfolio.number, portfolio.name, portfolio.targets);
- }
-
- /**
- * Convert a {@link Topology} into a runner-facing DTO.
- */
- public static org.opendc.web.proto.runner.Topology toDto(Topology topology) {
- return new org.opendc.web.proto.runner.Topology(
- topology.id, topology.number, topology.name, topology.rooms, topology.createdAt, topology.updatedAt);
- }
-}
diff --git a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/user/PortfolioResource.java b/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/user/PortfolioResource.java
deleted file mode 100644
index 2a3a40f4..00000000
--- a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/user/PortfolioResource.java
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
- * Copyright (c) 2023 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.web.server.rest.user;
-
-import io.quarkus.security.identity.SecurityIdentity;
-import jakarta.annotation.security.RolesAllowed;
-import jakarta.transaction.Transactional;
-import jakarta.validation.Valid;
-import jakarta.ws.rs.Consumes;
-import jakarta.ws.rs.DELETE;
-import jakarta.ws.rs.GET;
-import jakarta.ws.rs.POST;
-import jakarta.ws.rs.Path;
-import jakarta.ws.rs.PathParam;
-import jakarta.ws.rs.Produces;
-import jakarta.ws.rs.WebApplicationException;
-import java.time.Instant;
-import java.util.List;
-import org.opendc.web.server.model.Portfolio;
-import org.opendc.web.server.model.ProjectAuthorization;
-
-/**
- * A resource representing the portfolios of a project.
- */
-@Produces("application/json")
-@Path("/projects/{project}/portfolios")
-@RolesAllowed("openid")
-public final class PortfolioResource {
- /**
- * The identity of the current user.
- */
- private final SecurityIdentity identity;
-
- /**
- * Construct a {@link PortfolioResource}.
- *
- * @param identity The {@link SecurityIdentity} of the current user.
- */
- public PortfolioResource(SecurityIdentity identity) {
- this.identity = identity;
- }
-
- /**
- * Get all portfolios that belong to the specified project.
- */
- @GET
- public List<org.opendc.web.proto.user.Portfolio> getAll(@PathParam("project") long projectId) {
- // User must have access to project
- ProjectAuthorization auth =
- ProjectAuthorization.findByUser(identity.getPrincipal().getName(), projectId);
-
- if (auth == null) {
- return List.of();
- }
-
- return Portfolio.findByProject(projectId).list().stream()
- .map((p) -> UserProtocol.toDto(p, auth))
- .toList();
- }
-
- /**
- * Create a portfolio for this project.
- */
- @POST
- @Transactional
- @Consumes("application/json")
- public org.opendc.web.proto.user.Portfolio create(
- @PathParam("project") long projectId, @Valid org.opendc.web.proto.user.Portfolio.Create request) {
- // User must have access to project
- ProjectAuthorization auth =
- ProjectAuthorization.findByUser(identity.getPrincipal().getName(), projectId);
-
- if (auth == null) {
- throw new WebApplicationException("Project not found", 404);
- } else if (!auth.canEdit()) {
- throw new WebApplicationException("Not permitted to edit project", 403);
- }
-
- var now = Instant.now();
- var project = auth.project;
- int number = project.allocatePortfolio(now);
-
- Portfolio portfolio = new Portfolio(project, number, request.getName(), request.getTargets());
-
- project.portfolios.add(portfolio);
- portfolio.persist();
-
- return UserProtocol.toDto(portfolio, auth);
- }
-
- /**
- * Obtain a portfolio by its identifier.
- */
- @GET
- @Path("{portfolio}")
- public org.opendc.web.proto.user.Portfolio get(
- @PathParam("project") long projectId, @PathParam("portfolio") int number) {
- // User must have access to project
- ProjectAuthorization auth =
- ProjectAuthorization.findByUser(identity.getPrincipal().getName(), projectId);
-
- if (auth == null) {
- throw new WebApplicationException("Portfolio not found", 404);
- }
-
- Portfolio portfolio = Portfolio.findByProject(projectId, number);
-
- if (portfolio == null) {
- throw new WebApplicationException("Portfolio not found", 404);
- }
-
- return UserProtocol.toDto(portfolio, auth);
- }
-
- /**
- * Delete a portfolio.
- */
- @DELETE
- @Path("{portfolio}")
- @Transactional
- public org.opendc.web.proto.user.Portfolio delete(
- @PathParam("project") long projectId, @PathParam("portfolio") int number) {
- // User must have access to project
- ProjectAuthorization auth =
- ProjectAuthorization.findByUser(identity.getPrincipal().getName(), projectId);
-
- if (auth == null) {
- throw new WebApplicationException("Portfolio not found", 404);
- } else if (!auth.canEdit()) {
- throw new WebApplicationException("Not permitted to edit project", 403);
- }
-
- Portfolio entity = Portfolio.findByProject(projectId, number);
- if (entity == null) {
- throw new WebApplicationException("Portfolio not found", 404);
- }
-
- entity.delete();
- return UserProtocol.toDto(entity, auth);
- }
-}
diff --git a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/user/PortfolioScenarioResource.java b/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/user/PortfolioScenarioResource.java
deleted file mode 100644
index 789808c8..00000000
--- a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/user/PortfolioScenarioResource.java
+++ /dev/null
@@ -1,159 +0,0 @@
-/*
- * Copyright (c) 2023 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.web.server.rest.user;
-
-import io.quarkus.security.identity.SecurityIdentity;
-import jakarta.annotation.security.RolesAllowed;
-import jakarta.transaction.Transactional;
-import jakarta.validation.Valid;
-import jakarta.ws.rs.Consumes;
-import jakarta.ws.rs.GET;
-import jakarta.ws.rs.POST;
-import jakarta.ws.rs.Path;
-import jakarta.ws.rs.PathParam;
-import jakarta.ws.rs.Produces;
-import jakarta.ws.rs.WebApplicationException;
-import java.time.Instant;
-import java.util.List;
-import org.opendc.web.proto.JobState;
-import org.opendc.web.server.model.Job;
-import org.opendc.web.server.model.Portfolio;
-import org.opendc.web.server.model.ProjectAuthorization;
-import org.opendc.web.server.model.Scenario;
-import org.opendc.web.server.model.Topology;
-import org.opendc.web.server.model.Trace;
-import org.opendc.web.server.model.Workload;
-import org.opendc.web.server.service.UserAccountingService;
-
-/**
- * A resource representing the scenarios of a portfolio.
- */
-@Path("/projects/{project}/portfolios/{portfolio}/scenarios")
-@RolesAllowed("openid")
-@Produces("application/json")
-public final class PortfolioScenarioResource {
- /**
- * The service for managing the user accounting.
- */
- private final UserAccountingService accountingService;
-
- /**
- * The identity of the current user.
- */
- private final SecurityIdentity identity;
-
- /**
- * Construct a {@link PortfolioScenarioResource}.
- *
- * @param accountingService The {@link UserAccountingService} instance to use.
- * @param identity The {@link SecurityIdentity} of the current user.
- */
- public PortfolioScenarioResource(UserAccountingService accountingService, SecurityIdentity identity) {
- this.accountingService = accountingService;
- this.identity = identity;
- }
-
- /**
- * Get all scenarios that belong to the specified portfolio.
- */
- @GET
- public List<org.opendc.web.proto.user.Scenario> get(
- @PathParam("project") long projectId, @PathParam("portfolio") int portfolioNumber) {
- // User must have access to project
- ProjectAuthorization auth =
- ProjectAuthorization.findByUser(identity.getPrincipal().getName(), projectId);
-
- if (auth == null) {
- return List.of();
- }
-
- return org.opendc.web.server.model.Scenario.findByPortfolio(projectId, portfolioNumber).list().stream()
- .map((s) -> UserProtocol.toDto(s, auth))
- .toList();
- }
-
- /**
- * Create a scenario for this portfolio.
- */
- @POST
- @Transactional
- @Consumes("application/json")
- public org.opendc.web.proto.user.Scenario create(
- @PathParam("project") long projectId,
- @PathParam("portfolio") int portfolioNumber,
- @Valid org.opendc.web.proto.user.Scenario.Create request) {
- // User must have access to project
- String userId = identity.getPrincipal().getName();
- ProjectAuthorization auth = ProjectAuthorization.findByUser(userId, projectId);
-
- if (auth == null) {
- throw new WebApplicationException("Portfolio not found", 404);
- } else if (!auth.canEdit()) {
- throw new WebApplicationException("Not permitted to edit project", 403);
- }
-
- Portfolio portfolio = Portfolio.findByProject(projectId, portfolioNumber);
-
- if (portfolio == null) {
- throw new WebApplicationException("Portfolio not found", 404);
- }
-
- Topology topology = Topology.findByProject(projectId, (int) request.getTopology());
- if (topology == null) {
- throw new WebApplicationException("Referred topology does not exist", 400);
- }
-
- Trace trace = Trace.findById(request.getWorkload().getTrace());
- if (trace == null) {
- throw new WebApplicationException("Referred trace does not exist", 400);
- }
-
- var now = Instant.now();
- var project = auth.project;
- int number = project.allocateScenario(now);
-
- Scenario scenario = new Scenario(
- project,
- portfolio,
- number,
- request.getName(),
- new Workload(trace, request.getWorkload().getSamplingFraction()),
- topology,
- request.getPhenomena(),
- request.getSchedulerName());
- scenario.persist();
-
- Job job = new Job(scenario, userId, now, portfolio.targets.getRepeats());
- job.persist();
-
- // Fail the job if there is not enough budget for the simulation
- if (!accountingService.hasSimulationBudget(userId)) {
- job.state = JobState.FAILED;
- }
-
- scenario.jobs.add(job);
- portfolio.scenarios.add(scenario);
-
- return UserProtocol.toDto(scenario, auth);
- }
-}
diff --git a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/user/ProjectResource.java b/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/user/ProjectResource.java
deleted file mode 100644
index ae1c959e..00000000
--- a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/user/ProjectResource.java
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- * Copyright (c) 2023 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.web.server.rest.user;
-
-import io.quarkus.security.identity.SecurityIdentity;
-import jakarta.annotation.security.RolesAllowed;
-import jakarta.transaction.Transactional;
-import jakarta.validation.Valid;
-import jakarta.ws.rs.Consumes;
-import jakarta.ws.rs.DELETE;
-import jakarta.ws.rs.GET;
-import jakarta.ws.rs.POST;
-import jakarta.ws.rs.Path;
-import jakarta.ws.rs.PathParam;
-import jakarta.ws.rs.Produces;
-import jakarta.ws.rs.WebApplicationException;
-import java.time.Instant;
-import java.util.List;
-import org.opendc.web.proto.user.ProjectRole;
-import org.opendc.web.server.model.Project;
-import org.opendc.web.server.model.ProjectAuthorization;
-
-/**
- * A resource representing the created projects.
- */
-@Produces("application/json")
-@Path("/projects")
-@RolesAllowed("openid")
-public final class ProjectResource {
- /**
- * The identity of the current user.
- */
- private final SecurityIdentity identity;
-
- /**
- * Construct a {@link ProjectResource}.
- *
- * @param identity The {@link SecurityIdentity} of the current user.
- */
- public ProjectResource(SecurityIdentity identity) {
- this.identity = identity;
- }
-
- /**
- * Obtain all the projects of the current user.
- */
- @GET
- public List<org.opendc.web.proto.user.Project> getAll() {
- return ProjectAuthorization.findByUser(identity.getPrincipal().getName()).list().stream()
- .map(UserProtocol::toDto)
- .toList();
- }
-
- /**
- * Create a new project for the current user.
- */
- @POST
- @Transactional
- @Consumes("application/json")
- public org.opendc.web.proto.user.Project create(@Valid org.opendc.web.proto.user.Project.Create request) {
- Instant now = Instant.now();
- Project entity = new Project(request.getName(), now);
- entity.persist();
-
- ProjectAuthorization authorization =
- new ProjectAuthorization(entity, identity.getPrincipal().getName(), ProjectRole.OWNER);
-
- entity.authorizations.add(authorization);
- authorization.persist();
-
- return UserProtocol.toDto(authorization);
- }
-
- /**
- * Obtain a single project by its identifier.
- */
- @GET
- @Path("{project}")
- public org.opendc.web.proto.user.Project get(@PathParam("project") long project_id) {
- ProjectAuthorization auth =
- ProjectAuthorization.findByUser(identity.getPrincipal().getName(), project_id);
-
- if (auth == null) {
- throw new WebApplicationException("Project not found", 404);
- }
-
- return UserProtocol.toDto(auth);
- }
-
- /**
- * Delete a project.
- */
- @DELETE
- @Path("{project}")
- @Transactional
- public org.opendc.web.proto.user.Project delete(@PathParam("project") long id) {
- ProjectAuthorization auth =
- ProjectAuthorization.findByUser(identity.getPrincipal().getName(), id);
-
- if (auth == null) {
- throw new WebApplicationException("Project not found", 404);
- } else if (!auth.canDelete()) {
- throw new WebApplicationException("Not allowed to delete project", 403);
- }
-
- auth.project.updatedAt = Instant.now();
- org.opendc.web.proto.user.Project project = UserProtocol.toDto(auth);
- auth.project.delete();
- return project;
- }
-}
diff --git a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/user/ScenarioResource.java b/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/user/ScenarioResource.java
deleted file mode 100644
index bb3eb89b..00000000
--- a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/user/ScenarioResource.java
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * Copyright (c) 2023 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.web.server.rest.user;
-
-import io.quarkus.security.identity.SecurityIdentity;
-import jakarta.annotation.security.RolesAllowed;
-import jakarta.transaction.Transactional;
-import jakarta.ws.rs.DELETE;
-import jakarta.ws.rs.GET;
-import jakarta.ws.rs.Path;
-import jakarta.ws.rs.PathParam;
-import jakarta.ws.rs.Produces;
-import jakarta.ws.rs.WebApplicationException;
-import java.util.List;
-import org.opendc.web.server.model.ProjectAuthorization;
-import org.opendc.web.server.model.Scenario;
-
-/**
- * A resource representing the scenarios of a portfolio.
- */
-@Produces("application/json")
-@Path("/projects/{project}/scenarios")
-@RolesAllowed("openid")
-public final class ScenarioResource {
- /**
- * The identity of the current user.
- */
- private final SecurityIdentity identity;
-
- /**
- * Construct a {@link ScenarioResource}.
- *
- * @param identity The {@link SecurityIdentity} of the current user.
- */
- public ScenarioResource(SecurityIdentity identity) {
- this.identity = identity;
- }
-
- /**
- * Obtain the scenarios belonging to a project.
- */
- @GET
- public List<org.opendc.web.proto.user.Scenario> getAll(@PathParam("project") long projectId) {
- // User must have access to project
- ProjectAuthorization auth =
- ProjectAuthorization.findByUser(identity.getPrincipal().getName(), projectId);
-
- if (auth == null) {
- throw new WebApplicationException("Project not found", 404);
- }
-
- return Scenario.findByProject(projectId).list().stream()
- .map((s) -> UserProtocol.toDto(s, auth))
- .toList();
- }
-
- /**
- * Obtain a scenario by its identifier.
- */
- @GET
- @Path("{scenario}")
- public org.opendc.web.proto.user.Scenario get(
- @PathParam("project") long projectId, @PathParam("scenario") int number) {
- // User must have access to project
- ProjectAuthorization auth =
- ProjectAuthorization.findByUser(identity.getPrincipal().getName(), projectId);
-
- if (auth == null) {
- throw new WebApplicationException("Project not found", 404);
- }
-
- Scenario scenario = Scenario.findByProject(projectId, number);
-
- if (scenario == null) {
- throw new WebApplicationException("Scenario not found", 404);
- }
-
- return UserProtocol.toDto(scenario, auth);
- }
-
- /**
- * Delete a scenario.
- */
- @DELETE
- @Path("{scenario}")
- @Transactional
- public org.opendc.web.proto.user.Scenario delete(
- @PathParam("project") long projectId, @PathParam("scenario") int number) {
- // User must have access to project
- ProjectAuthorization auth =
- ProjectAuthorization.findByUser(identity.getPrincipal().getName(), projectId);
-
- if (auth == null) {
- throw new WebApplicationException("Project not found", 404);
- } else if (!auth.canEdit()) {
- throw new WebApplicationException("Not permitted to edit project", 403);
- }
-
- Scenario entity = Scenario.findByProject(projectId, number);
- if (entity == null) {
- throw new WebApplicationException("Scenario not found", 404);
- }
-
- entity.delete();
- return UserProtocol.toDto(entity, auth);
- }
-}
diff --git a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/user/TopologyResource.java b/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/user/TopologyResource.java
deleted file mode 100644
index b8c542d3..00000000
--- a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/user/TopologyResource.java
+++ /dev/null
@@ -1,208 +0,0 @@
-/*
- * Copyright (c) 2023 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.web.server.rest.user;
-
-import io.quarkus.hibernate.orm.panache.Panache;
-import io.quarkus.security.identity.SecurityIdentity;
-import jakarta.annotation.security.RolesAllowed;
-import jakarta.persistence.PersistenceException;
-import jakarta.transaction.Transactional;
-import jakarta.validation.Valid;
-import jakarta.ws.rs.Consumes;
-import jakarta.ws.rs.DELETE;
-import jakarta.ws.rs.GET;
-import jakarta.ws.rs.POST;
-import jakarta.ws.rs.PUT;
-import jakarta.ws.rs.Path;
-import jakarta.ws.rs.PathParam;
-import jakarta.ws.rs.Produces;
-import jakarta.ws.rs.WebApplicationException;
-import java.time.Instant;
-import java.util.List;
-import org.opendc.web.server.model.Project;
-import org.opendc.web.server.model.ProjectAuthorization;
-import org.opendc.web.server.model.Topology;
-
-/**
- * A resource representing the constructed datacenter topologies.
- */
-@Produces("application/json")
-@Path("/projects/{project}/topologies")
-@RolesAllowed("openid")
-public final class TopologyResource {
- /**
- * The identity of the current user.
- */
- private final SecurityIdentity identity;
-
- /**
- * Construct a {@link TopologyResource}.
- *
- * @param identity The {@link SecurityIdentity} of the current user.
- */
- public TopologyResource(SecurityIdentity identity) {
- this.identity = identity;
- }
-
- /**
- * Get all topologies that belong to the specified project.
- */
- @GET
- public List<org.opendc.web.proto.user.Topology> getAll(@PathParam("project") long projectId) {
- // User must have access to project
- ProjectAuthorization auth =
- ProjectAuthorization.findByUser(identity.getPrincipal().getName(), projectId);
-
- if (auth == null) {
- return List.of();
- }
-
- return Topology.findByProject(projectId).list().stream()
- .map((t) -> UserProtocol.toDto(t, auth))
- .toList();
- }
-
- /**
- * Create a topology for this project.
- */
- @POST
- @Consumes("application/json")
- @Transactional
- public org.opendc.web.proto.user.Topology create(
- @PathParam("project") long projectId, @Valid org.opendc.web.proto.user.Topology.Create request) {
- // User must have access to project
- ProjectAuthorization auth =
- ProjectAuthorization.findByUser(identity.getPrincipal().getName(), projectId);
-
- if (auth == null) {
- throw new WebApplicationException("Topology not found", 404);
- } else if (!auth.canEdit()) {
- throw new WebApplicationException("Not permitted to edit project", 403);
- }
-
- Instant now = Instant.now();
- Project project = auth.project;
- int number = project.allocateTopology(now);
-
- Topology topology = new Topology(project, number, request.getName(), now, request.getRooms());
-
- project.topologies.add(topology);
- topology.persist();
-
- return UserProtocol.toDto(topology, auth);
- }
-
- /**
- * Obtain a topology by its number.
- */
- @GET
- @Path("{topology}")
- public org.opendc.web.proto.user.Topology get(
- @PathParam("project") long projectId, @PathParam("topology") int number) {
- // User must have access to project
- ProjectAuthorization auth =
- ProjectAuthorization.findByUser(identity.getPrincipal().getName(), projectId);
-
- if (auth == null) {
- throw new WebApplicationException("Topology not found", 404);
- }
-
- Topology topology = Topology.findByProject(projectId, number);
-
- if (topology == null) {
- throw new WebApplicationException("Topology not found", 404);
- }
-
- return UserProtocol.toDto(topology, auth);
- }
-
- /**
- * Update the specified topology by its number.
- */
- @PUT
- @Path("{topology}")
- @Consumes("application/json")
- @Transactional
- public org.opendc.web.proto.user.Topology update(
- @PathParam("project") long projectId,
- @PathParam("topology") int number,
- @Valid org.opendc.web.proto.user.Topology.Update request) {
- // User must have access to project
- ProjectAuthorization auth =
- ProjectAuthorization.findByUser(identity.getPrincipal().getName(), projectId);
-
- if (auth == null) {
- throw new WebApplicationException("Topology not found", 404);
- } else if (!auth.canEdit()) {
- throw new WebApplicationException("Not permitted to edit project", 403);
- }
-
- Topology entity = Topology.findByProject(projectId, number);
-
- if (entity == null) {
- throw new WebApplicationException("Topology not found", 404);
- }
-
- entity.updatedAt = Instant.now();
- entity.rooms = request.getRooms();
-
- return UserProtocol.toDto(entity, auth);
- }
-
- /**
- * Delete the specified topology.
- */
- @Path("{topology}")
- @DELETE
- @Transactional
- public org.opendc.web.proto.user.Topology delete(
- @PathParam("project") long projectId, @PathParam("topology") int number) {
- // User must have access to project
- ProjectAuthorization auth =
- ProjectAuthorization.findByUser(identity.getPrincipal().getName(), projectId);
-
- if (auth == null) {
- throw new WebApplicationException("Topology not found", 404);
- } else if (!auth.canEdit()) {
- throw new WebApplicationException("Not permitted to edit project", 403);
- }
-
- Topology entity = Topology.findByProject(projectId, number);
-
- if (entity == null) {
- throw new WebApplicationException("Topology not found", 404);
- }
-
- entity.updatedAt = Instant.now();
- entity.delete();
-
- try {
- // Flush the results, so we can check whether the constraints are not violated
- Panache.flush();
- } catch (PersistenceException e) {
- throw new WebApplicationException("Topology is still in use", 403);
- }
-
- return UserProtocol.toDto(entity, auth);
- }
-}
diff --git a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/user/UserProtocol.java b/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/user/UserProtocol.java
deleted file mode 100644
index 8196a9d6..00000000
--- a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/user/UserProtocol.java
+++ /dev/null
@@ -1,132 +0,0 @@
-/*
- * Copyright (c) 2023 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.web.server.rest.user;
-
-import org.opendc.web.server.model.Job;
-import org.opendc.web.server.model.Portfolio;
-import org.opendc.web.server.model.Project;
-import org.opendc.web.server.model.ProjectAuthorization;
-import org.opendc.web.server.model.Scenario;
-import org.opendc.web.server.model.Topology;
-import org.opendc.web.server.rest.BaseProtocol;
-
-/**
- * DTO-conversions for the user protocol.
- */
-public final class UserProtocol {
- /**
- * Private constructor to prevent instantiation of class.
- */
- private UserProtocol() {}
-
- /**
- * Convert a {@link ProjectAuthorization} entity into a {@link Project} DTO.
- */
- public static org.opendc.web.proto.user.Project toDto(ProjectAuthorization auth) {
- Project project = auth.project;
- return new org.opendc.web.proto.user.Project(
- project.id, project.name, project.createdAt, project.updatedAt, auth.role);
- }
-
- /**
- * Convert a {@link Portfolio} entity into a {@link org.opendc.web.proto.user.Portfolio} DTO.
- */
- public static org.opendc.web.proto.user.Portfolio toDto(Portfolio portfolio, ProjectAuthorization auth) {
- return new org.opendc.web.proto.user.Portfolio(
- portfolio.id,
- portfolio.number,
- toDto(auth),
- portfolio.name,
- portfolio.targets,
- portfolio.scenarios.stream().map(UserProtocol::toSummaryDto).toList());
- }
-
- /**
- * Convert a {@link Portfolio} entity into a {@link org.opendc.web.proto.user.Portfolio.Summary} DTO.
- */
- public static org.opendc.web.proto.user.Portfolio.Summary toSummaryDto(Portfolio portfolio) {
- return new org.opendc.web.proto.user.Portfolio.Summary(
- portfolio.id, portfolio.number, portfolio.name, portfolio.targets);
- }
-
- /**
- * Convert a {@link Topology} entity into a {@link org.opendc.web.proto.user.Topology} DTO.
- */
- public static org.opendc.web.proto.user.Topology toDto(Topology topology, ProjectAuthorization auth) {
- return new org.opendc.web.proto.user.Topology(
- topology.id,
- topology.number,
- toDto(auth),
- topology.name,
- topology.rooms,
- topology.createdAt,
- topology.updatedAt);
- }
-
- /**
- * Convert a {@link Topology} entity into a {@link org.opendc.web.proto.user.Topology.Summary} DTO.
- */
- public static org.opendc.web.proto.user.Topology.Summary toSummaryDto(Topology topology) {
- return new org.opendc.web.proto.user.Topology.Summary(
- topology.id, topology.number, topology.name, topology.createdAt, topology.updatedAt);
- }
-
- /**
- * Convert a {@link Scenario} entity into a {@link org.opendc.web.proto.user.Scenario} DTO.
- */
- public static org.opendc.web.proto.user.Scenario toDto(Scenario scenario, ProjectAuthorization auth) {
- return new org.opendc.web.proto.user.Scenario(
- scenario.id,
- scenario.number,
- toDto(auth),
- toSummaryDto(scenario.portfolio),
- scenario.name,
- BaseProtocol.toDto(scenario.workload),
- toSummaryDto(scenario.topology),
- scenario.phenomena,
- scenario.schedulerName,
- scenario.jobs.stream().map(UserProtocol::toDto).toList());
- }
-
- /**
- * Convert a {@link Scenario} entity into a {@link org.opendc.web.proto.user.Scenario.Summary} DTO.
- */
- public static org.opendc.web.proto.user.Scenario.Summary toSummaryDto(Scenario scenario) {
- return new org.opendc.web.proto.user.Scenario.Summary(
- scenario.id,
- scenario.number,
- scenario.name,
- BaseProtocol.toDto(scenario.workload),
- toSummaryDto(scenario.topology),
- scenario.phenomena,
- scenario.schedulerName,
- scenario.jobs.stream().map(UserProtocol::toDto).toList());
- }
-
- /**
- * Convert a {@link Job} entity into a {@link org.opendc.web.proto.user.Job} DTO.
- */
- public static org.opendc.web.proto.user.Job toDto(Job job) {
- return new org.opendc.web.proto.user.Job(job.id, job.state, job.createdAt, job.updatedAt, job.results);
- }
-}
diff --git a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/user/UserResource.java b/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/user/UserResource.java
deleted file mode 100644
index c8cda2b7..00000000
--- a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/user/UserResource.java
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Copyright (c) 2023 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.web.server.rest.user;
-
-import io.quarkus.security.identity.SecurityIdentity;
-import jakarta.annotation.security.RolesAllowed;
-import jakarta.ws.rs.GET;
-import jakarta.ws.rs.Path;
-import jakarta.ws.rs.Produces;
-import org.opendc.web.proto.user.User;
-import org.opendc.web.proto.user.UserAccounting;
-import org.opendc.web.server.service.UserAccountingService;
-
-/**
- * A resource representing the active user.
- */
-@Produces("application/json")
-@Path("/users")
-@RolesAllowed("openid")
-public final class UserResource {
- /**
- * The service for managing the user accounting.
- */
- private final UserAccountingService accountingService;
-
- /**
- * The identity of the current user.
- */
- private final SecurityIdentity identity;
-
- /**
- * Construct a {@link UserResource}.
- *
- * @param accountingService The {@link UserAccountingService} instance to use.
- * @param identity The {@link SecurityIdentity} of the current user.
- */
- public UserResource(UserAccountingService accountingService, SecurityIdentity identity) {
- this.accountingService = accountingService;
- this.identity = identity;
- }
-
- /**
- * Get the current active user data.
- */
- @GET
- @Path("me")
- public User get() {
- String userId = identity.getPrincipal().getName();
- UserAccounting accounting = accountingService.getAccounting(userId);
-
- return new User(userId, accounting);
- }
-}
diff --git a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/service/JobService.java b/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/service/JobService.java
deleted file mode 100644
index 70933520..00000000
--- a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/service/JobService.java
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Copyright (c) 2023 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.web.server.service;
-
-import jakarta.enterprise.context.ApplicationScoped;
-import java.time.Instant;
-import java.util.Map;
-import org.opendc.web.proto.JobState;
-import org.opendc.web.server.model.Job;
-
-/**
- * A service for managing the lifecycle of a job and ensuring that the user does not consume
- * too much simulation resources.
- */
-@ApplicationScoped
-public final class JobService {
- /**
- * The {@link UserAccountingService} responsible for accounting the simulation time of users.
- */
- private final UserAccountingService accountingService;
-
- /**
- * Construct a {@link JobService} instance.
- *
- * @param accountingService The {@link UserAccountingService} for accounting the simulation time of users.
- */
- public JobService(UserAccountingService accountingService) {
- this.accountingService = accountingService;
- }
-
- /**
- * Update the job state.
- *
- * @param job The {@link Job} to update.
- * @param newState The new state to transition the job to.
- * @param runtime The runtime (in seconds) consumed by the simulation jbo so far.
- * @param results The results to attach to the job.
- * @throws IllegalArgumentException if the state transition is invalid.
- * @throws IllegalStateException if someone tries to update the job concurrently.
- */
- public void updateJob(Job job, JobState newState, int runtime, Map<String, ?> results) {
- JobState state = job.state;
-
- if (!job.canTransitionTo(newState)) {
- throw new IllegalArgumentException("Invalid transition from %s to %s".formatted(state, newState));
- }
-
- Instant now = Instant.now();
- JobState nextState = newState;
- int consumedBudget = Math.min(1, runtime - job.runtime);
-
- // Check whether the user still has any simulation budget left
- if (accountingService.consumeSimulationBudget(job.createdBy, consumedBudget) && nextState == JobState.RUNNING) {
- nextState = JobState.FAILED; // User has consumed all their budget; cancel the job
- }
-
- if (!job.updateAtomically(nextState, now, runtime, results)) {
- throw new IllegalStateException("Conflicting update");
- }
- }
-}
diff --git a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/service/UserAccountingService.java b/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/service/UserAccountingService.java
deleted file mode 100644
index 73fa2a3e..00000000
--- a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/service/UserAccountingService.java
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
- * Copyright (c) 2023 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.web.server.service;
-
-import jakarta.enterprise.context.ApplicationScoped;
-import jakarta.persistence.EntityExistsException;
-import java.time.Duration;
-import java.time.LocalDate;
-import java.time.temporal.TemporalAdjusters;
-import org.eclipse.microprofile.config.inject.ConfigProperty;
-import org.opendc.web.server.model.UserAccounting;
-
-/**
- * Service to track the simulation budget of users.
- */
-@ApplicationScoped
-public final class UserAccountingService {
- /**
- * The default simulation budget for new users.
- */
- private final Duration simulationBudget;
-
- /**
- * Construct a {@link UserAccountingService} instance.
- *
- * @param simulationBudget The default simulation budget for new users.
- */
- public UserAccountingService(
- @ConfigProperty(name = "opendc.accounting.simulation-budget", defaultValue = "2000m")
- Duration simulationBudget) {
- this.simulationBudget = simulationBudget;
- }
-
- /**
- * Return the {@link org.opendc.web.proto.user.UserAccounting} object for the user with the
- * specified <code>userId</code>. If the object does not exist in the database, a default value is constructed.
- */
- public org.opendc.web.proto.user.UserAccounting getAccounting(String userId) {
- UserAccounting accounting = UserAccounting.findByUser(userId);
- if (accounting != null) {
- return new org.opendc.web.proto.user.UserAccounting(
- accounting.periodEnd, accounting.simulationTime, accounting.simulationTimeBudget);
- }
-
- return new org.opendc.web.proto.user.UserAccounting(
- getNextAccountingPeriod(LocalDate.now()), 0, (int) simulationBudget.toSeconds());
- }
-
- /**
- * Determine whether the user with <code>userId</code> has any remaining simulation budget.
- *
- * @param userId The unique identifier of the user.
- * @return <code>true</code> when the user still has budget left, <code>false</code> otherwise.
- */
- public boolean hasSimulationBudget(String userId) {
- UserAccounting accounting = UserAccounting.findByUser(userId);
- if (accounting == null) {
- return true;
- }
- return accounting.hasSimulationBudget();
- }
-
- /**
- * Consume <code>seconds</code> from the simulation budget of the user with <code>userId</code>.
- *
- * @param userId The unique identifier of the user.
- * @param seconds The seconds to consume from the simulation budget.
- * @return <code>true</code> if the user has consumed his full budget or <code>false</code> if there is still budget
- * remaining.
- */
- public boolean consumeSimulationBudget(String userId, int seconds) {
- LocalDate today = LocalDate.now();
- LocalDate nextAccountingPeriod = getNextAccountingPeriod(today);
-
- // We need to be careful to prevent conflicts in case of concurrency
- // 1. First, we try to create the accounting object if it does not exist yet. This may fail if another instance
- // creates the object concurrently.
- // 2. Second, we check if the budget needs to be reset and try this atomically.
- // 3. Finally, we atomically consume the budget from the object
- // This is repeated three times in case there is a conflict
- for (int i = 0; i < 3; i++) {
- UserAccounting accounting = UserAccounting.findByUser(userId);
-
- if (accounting == null) {
- try {
- UserAccounting newAccounting = UserAccounting.create(
- userId, nextAccountingPeriod, (int) simulationBudget.toSeconds(), seconds);
- return !newAccounting.hasSimulationBudget();
- } catch (EntityExistsException e) {
- // Conflict due to concurrency; retry
- }
- } else {
- boolean success;
-
- if (!today.isBefore(accounting.periodEnd)) {
- success = accounting.resetBudget(nextAccountingPeriod, seconds);
- } else {
- success = accounting.consumeBudget(seconds);
- }
-
- if (success) {
- return !accounting.hasSimulationBudget();
- }
- }
- }
-
- throw new IllegalStateException("Failed to allocate consume budget due to conflict");
- }
-
- /**
- * Helper method to find next accounting period.
- */
- private static LocalDate getNextAccountingPeriod(LocalDate today) {
- return today.with(TemporalAdjusters.firstDayOfNextMonth());
- }
-}
diff --git a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/util/DevSecurityOverrideFilter.java b/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/util/DevSecurityOverrideFilter.java
deleted file mode 100644
index 103f868d..00000000
--- a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/util/DevSecurityOverrideFilter.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright (c) 2021 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.web.server.util;
-
-import io.quarkus.arc.properties.IfBuildProperty;
-import jakarta.ws.rs.container.ContainerRequestContext;
-import jakarta.ws.rs.container.ContainerRequestFilter;
-import jakarta.ws.rs.container.PreMatching;
-import jakarta.ws.rs.core.SecurityContext;
-import jakarta.ws.rs.ext.Provider;
-import java.security.Principal;
-
-/**
- * Helper class to disable security for the OpenDC web API when in development mode.
- */
-@Provider
-@PreMatching
-@IfBuildProperty(name = "opendc.security.enabled", stringValue = "false")
-public class DevSecurityOverrideFilter implements ContainerRequestFilter {
- @Override
- public void filter(ContainerRequestContext requestContext) {
- requestContext.setSecurityContext(new SecurityContext() {
- @Override
- public Principal getUserPrincipal() {
- return () -> "anon";
- }
-
- @Override
- public boolean isUserInRole(String role) {
- return true;
- }
-
- @Override
- public boolean isSecure() {
- return false;
- }
-
- @Override
- public String getAuthenticationScheme() {
- return "basic";
- }
- });
- }
-}
diff --git a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/util/KotlinModuleCustomizer.java b/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/util/KotlinModuleCustomizer.java
deleted file mode 100644
index ff3ba1cd..00000000
--- a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/util/KotlinModuleCustomizer.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (c) 2023 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.web.server.util;
-
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.fasterxml.jackson.module.kotlin.KotlinModule;
-import io.quarkus.jackson.ObjectMapperCustomizer;
-import jakarta.inject.Singleton;
-
-/**
- * Helper class to register the Kotlin Jackson module.
- */
-@Singleton
-public final class KotlinModuleCustomizer implements ObjectMapperCustomizer {
- @Override
- public void customize(ObjectMapper objectMapper) {
- objectMapper.registerModule(new KotlinModule.Builder().build());
- }
-}
diff --git a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/util/QuarkusObjectMapperSupplier.java b/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/util/QuarkusObjectMapperSupplier.java
deleted file mode 100644
index 60ca77e5..00000000
--- a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/util/QuarkusObjectMapperSupplier.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (c) 2023 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.web.server.util;
-
-import com.fasterxml.jackson.databind.ObjectMapper;
-import io.hypersistence.utils.hibernate.type.util.ObjectMapperSupplier;
-import io.quarkus.runtime.annotations.RegisterForReflection;
-import jakarta.enterprise.inject.spi.CDI;
-
-/**
- * A supplier for an {@link ObjectMapper} used by the Hypersistence utilities.
- */
-@RegisterForReflection
-public class QuarkusObjectMapperSupplier implements ObjectMapperSupplier {
- @Override
- public ObjectMapper get() {
- return CDI.current().select(ObjectMapper.class).get();
- }
-}
diff --git a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/util/runner/QuarkusJobManager.java b/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/util/runner/QuarkusJobManager.java
deleted file mode 100644
index 47d397f3..00000000
--- a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/util/runner/QuarkusJobManager.java
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * Copyright (c) 2022 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.web.server.util.runner;
-
-import jakarta.enterprise.context.ApplicationScoped;
-import jakarta.transaction.Transactional;
-import java.util.Map;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-import org.opendc.web.proto.JobState;
-import org.opendc.web.runner.JobManager;
-import org.opendc.web.server.model.Job;
-import org.opendc.web.server.rest.runner.RunnerProtocol;
-import org.opendc.web.server.service.JobService;
-
-/**
- * Implementation of {@link JobManager} that interfaces directly with the database without overhead of the REST API.
- */
-@ApplicationScoped
-public class QuarkusJobManager implements JobManager {
- /**
- * The {@link JobService} used to manage the job's lifecycle.
- */
- private final JobService jobService;
-
- /**
- * Construct a {@link QuarkusJobManager}.
- *
- * @param jobService The {@link JobService} for managing the job's lifecycle.
- */
- public QuarkusJobManager(JobService jobService) {
- this.jobService = jobService;
- }
-
- @Transactional
- @Nullable
- @Override
- public org.opendc.web.proto.runner.Job findNext() {
- var job = Job.findByState(JobState.PENDING).firstResult();
- if (job == null) {
- return null;
- }
-
- return RunnerProtocol.toDto(job);
- }
-
- @Transactional
- @Override
- public boolean claim(long id) {
- return updateState(id, JobState.CLAIMED, 0, null);
- }
-
- @Transactional
- @Override
- public boolean heartbeat(long id, int runtime) {
- return updateState(id, JobState.RUNNING, runtime, null);
- }
-
- @Transactional
- @Override
- public void fail(long id, int runtime) {
- updateState(id, JobState.FAILED, runtime, null);
- }
-
- @Transactional
- @Override
- public void finish(long id, int runtime, @NotNull Map<String, ?> results) {
- updateState(id, JobState.FINISHED, runtime, results);
- }
-
- /**
- * Helper method to update the state of a job.
- *
- * @param id The unique id of the job.
- * @param newState The new state to transition to.
- * @param runtime The runtime of the job.
- * @param results The results of the job.
- * @return <code>true</code> if the operation succeeded, <code>false</code> otherwise.
- */
- private boolean updateState(long id, JobState newState, int runtime, Map<String, ?> results) {
- Job job = Job.findById(id);
-
- if (job == null) {
- return false;
- }
-
- try {
- jobService.updateJob(job, newState, runtime, results);
- return true;
- } catch (IllegalArgumentException | IllegalStateException e) {
- return false;
- }
- }
-}
diff --git a/opendc-web/opendc-web-server/src/main/resources/META-INF/branding/logo.png b/opendc-web/opendc-web-server/src/main/resources/META-INF/branding/logo.png
deleted file mode 100644
index d743038b..00000000
--- a/opendc-web/opendc-web-server/src/main/resources/META-INF/branding/logo.png
+++ /dev/null
Binary files differ
diff --git a/opendc-web/opendc-web-server/src/main/resources/application-dev.properties b/opendc-web/opendc-web-server/src/main/resources/application-dev.properties
deleted file mode 100644
index 5fbc4c04..00000000
--- a/opendc-web/opendc-web-server/src/main/resources/application-dev.properties
+++ /dev/null
@@ -1,36 +0,0 @@
-# Copyright (c) 2022 AtLarge Research
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in all
-# copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-# SOFTWARE.
-
-# Datasource (H2)
-quarkus.datasource.db-kind=h2
-quarkus.datasource.jdbc.url=jdbc:h2:mem:default;DB_CLOSE_DELAY=-1;INIT=CREATE TYPE IF NOT EXISTS "JSONB" AS json;
-
-# Hibernate
-quarkus.hibernate-orm.dialect=org.hibernate.dialect.H2Dialect
-quarkus.flyway.clean-at-start=true
-
-# Disable authentication
-opendc.security.enabled=false
-
-# Mount web UI at root and API at "/api"
-quarkus.resteasy.path=/api
-
-# Swagger UI
-quarkus.smallrye-openapi.servers=http://localhost:8080
diff --git a/opendc-web/opendc-web-server/src/main/resources/application-docker.properties b/opendc-web/opendc-web-server/src/main/resources/application-docker.properties
deleted file mode 100644
index eae9ee1e..00000000
--- a/opendc-web/opendc-web-server/src/main/resources/application-docker.properties
+++ /dev/null
@@ -1,49 +0,0 @@
-# Copyright (c) 2022 AtLarge Research
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in all
-# copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-# SOFTWARE.
-
-# Configuration for standalone Docker server distribution without web UI.
-
-# Datasource
-quarkus.datasource.db-kind=postgresql
-quarkus.datasource.username=${OPENDC_DB_USERNAME}
-quarkus.datasource.password=${OPENDC_DB_PASSWORD}
-quarkus.datasource.jdbc.url=${OPENDC_DB_URL}
-
-# Hibernate
-quarkus.hibernate-orm.dialect=org.hibernate.dialect.PostgreSQL95Dialect
-
-# Disable OpenDC web UI
-quarkus.opendc-ui.include=false
-
-# Security
-opendc.security.enabled=true
-quarkus.oidc.auth-server-url=https://${OPENDC_AUTH0_DOMAIN}
-quarkus.oidc.client-id=${OPENDC_AUTH0_AUDIENCE}
-quarkus.oidc.token.audience=${quarkus.oidc.client-id}
-quarkus.oidc.roles.role-claim-path=scope
-
-# Swagger UI
-quarkus.swagger-ui.oauth-client-id=${OPENDC_AUTH0_DOCS_CLIENT_ID:}
-quarkus.swagger-ui.oauth-additional-query-string-params={"audience":"${OPENDC_AUTH0_AUDIENCE:https://api.opendc.org/v2/}"}
-
-quarkus.smallrye-openapi.security-scheme=oidc
-quarkus.smallrye-openapi.security-scheme-name=Auth0
-quarkus.smallrye-openapi.oidc-open-id-connect-url=https://${OPENDC_AUTH0_DOMAIN:opendc.eu.auth0.com}/.well-known/openid-configuration
-quarkus.smallrye-openapi.servers=https://api.opendc.org
diff --git a/opendc-web/opendc-web-server/src/main/resources/application-prod.properties b/opendc-web/opendc-web-server/src/main/resources/application-prod.properties
deleted file mode 100644
index fe997fc0..00000000
--- a/opendc-web/opendc-web-server/src/main/resources/application-prod.properties
+++ /dev/null
@@ -1,36 +0,0 @@
-# Copyright (c) 2022 AtLarge Research
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in all
-# copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-# SOFTWARE.
-
-# Datasource (H2)
-quarkus.datasource.db-kind=h2
-quarkus.datasource.jdbc.url=jdbc:h2:file:./data/opendc;DB_CLOSE_DELAY=-1;INIT=CREATE TYPE IF NOT EXISTS "JSONB" AS json;
-
-# Hibernate
-quarkus.hibernate-orm.dialect=org.hibernate.dialect.H2Dialect
-
-# Disable authentication
-opendc.security.enabled=false
-quarkus.oidc.enabled=${opendc.security.enabled}
-
-# Mount web UI at root and API at "/api"
-quarkus.resteasy.path=/api
-
-# Swagger UI
-quarkus.smallrye-openapi.servers=http://localhost:8080
diff --git a/opendc-web/opendc-web-server/src/main/resources/application-test.properties b/opendc-web/opendc-web-server/src/main/resources/application-test.properties
deleted file mode 100644
index 4e3063e4..00000000
--- a/opendc-web/opendc-web-server/src/main/resources/application-test.properties
+++ /dev/null
@@ -1,43 +0,0 @@
-# Copyright (c) 2022 AtLarge Research
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in all
-# copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-# SOFTWARE.
-
-# Datasource configuration
-quarkus.datasource.db-kind = h2
-quarkus.datasource.jdbc.url=jdbc:h2:mem:default;DB_CLOSE_DELAY=-1;INIT=CREATE TYPE IF NOT EXISTS "JSONB" AS json;
-
-quarkus.hibernate-orm.dialect=org.hibernate.dialect.H2Dialect
-quarkus.hibernate-orm.log.sql=true
-quarkus.flyway.clean-at-start=true
-quarkus.flyway.locations=db/migration,db/testing
-
-# Disable security
-quarkus.oidc.enabled=false
-
-# Disable OpenAPI/Swagger
-quarkus.smallrye-openapi.enable=false
-quarkus.swagger-ui.enable=false
-
-# Disable OpenDC web UI and runner
-quarkus.opendc-ui.include=false
-quarkus.opendc-runner.include=false
-
-# Create new tables and fill them
-quarkus.hibernate-orm.database.generation=drop-and-create
-quarkus.hibernate-orm.sql-load-script=load_data.sql
diff --git a/opendc-web/opendc-web-server/src/main/resources/application.properties b/opendc-web/opendc-web-server/src/main/resources/application.properties
deleted file mode 100644
index 0f47db30..00000000
--- a/opendc-web/opendc-web-server/src/main/resources/application.properties
+++ /dev/null
@@ -1,49 +0,0 @@
-# Copyright (c) 2022 AtLarge Research
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in all
-# copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-# SOFTWARE.
-
-# Enable CORS
-quarkus.http.cors=true
-quarkus.http.cors.origins=http://localhost:3000,https://opendc.org
-
-# Security
-quarkus.oidc.enabled=${opendc.security.enabled}
-
-# Runner logging
-quarkus.log.category."org.opendc".level=ERROR
-quarkus.log.category."org.opendc.web".level=INFO
-quarkus.log.category."org.apache".level=WARN
-
-# OpenAPI and Swagger
-quarkus.smallrye-openapi.info-title=OpenDC REST API
-%dev.quarkus.smallrye-openapi.info-title=OpenDC REST API (development)
-quarkus.smallrye-openapi.info-version=2.1-rc1
-quarkus.smallrye-openapi.info-description=OpenDC is an open-source datacenter simulator for education, featuring real-time online collaboration, diverse simulation models, and detailed performance feedback statistics.
-quarkus.smallrye-openapi.info-contact-email=opendc@atlarge-research.com
-quarkus.smallrye-openapi.info-contact-name=OpenDC Support
-quarkus.smallrye-openapi.info-contact-url=https://opendc.org
-quarkus.smallrye-openapi.info-license-name=MIT
-quarkus.smallrye-openapi.info-license-url=https://github.com/atlarge-research/opendc/blob/master/LICENSE.txt
-
-quarkus.swagger-ui.path=docs
-quarkus.swagger-ui.always-include=true
-
-# Flyway database migrations
-quarkus.flyway.baseline-on-migrate=true
-quarkus.flyway.migrate-at-start=true
diff --git a/opendc-web/opendc-web-server/src/main/resources/hypersistence-utils.properties b/opendc-web/opendc-web-server/src/main/resources/hypersistence-utils.properties
deleted file mode 100644
index 451ce2d8..00000000
--- a/opendc-web/opendc-web-server/src/main/resources/hypersistence-utils.properties
+++ /dev/null
@@ -1 +0,0 @@
-hypersistence.utils.jackson.object.mapper=org.opendc.web.server.util.QuarkusObjectMapperSupplier
diff --git a/opendc-web/opendc-web-server/src/main/resources/load_data.sql b/opendc-web/opendc-web-server/src/main/resources/load_data.sql
deleted file mode 100644
index 72396cef..00000000
--- a/opendc-web/opendc-web-server/src/main/resources/load_data.sql
+++ /dev/null
@@ -1,124 +0,0 @@
-
--- Insert data
-
-INSERT INTO PROJECT (created_at, name, portfolios_created, scenarios_created, topologies_created, updated_at, id)
- VALUES ('2024-03-01T15:31:41.579969Z', 'Test Project 1', 0, 0, 0, '2024-03-01T15:31:41.579969Z', 1);
-
-INSERT INTO PROJECTAUTHORIZATION (role, project_id, user_name)
-VALUES ('OWNER', 1, 'test_user_1');
-
--- Add test user 2 as a viewer for project 1
-
-INSERT INTO PROJECTAUTHORIZATION (role, project_id, user_name)
-VALUES ('VIEWER', 1, 'test_user_2');
-
--- Add test user 3 as an editor for project 1
-
-INSERT INTO PROJECTAUTHORIZATION (role, project_id, user_name)
-VALUES ('EDITOR', 1, 'test_user_3');
-
--- Create a project for test user 2
-
-INSERT INTO PROJECT (created_at, name, portfolios_created, scenarios_created, topologies_created, updated_at, id)
-VALUES ('2024-03-01T15:31:41.579969Z', 'Test Project 2', 0, 0, 0, '2024-03-01T15:31:41.579969Z', 2);
-
-INSERT INTO PROJECTAUTHORIZATION (role, project_id, user_name)
-VALUES ('OWNER', 2, 'test_user_2');
-
--- Create three projects for test user 3. User 3 has multiple projects to test getAll
-
-INSERT INTO PROJECT (created_at, name, portfolios_created, scenarios_created, topologies_created, updated_at, id)
-VALUES ('2024-03-01T15:31:41.579969Z', 'Test Project 3', 0, 0, 0, '2024-03-01T15:31:41.579969Z', 3);
-
-INSERT INTO PROJECTAUTHORIZATION (role, project_id, user_name)
-VALUES ('OWNER', 3, 'test_user_3');
-
-INSERT INTO PROJECT (created_at, name, portfolios_created, scenarios_created, topologies_created, updated_at, id)
-VALUES ('2024-03-01T15:31:41.579969Z', 'Test Project 4', 0, 0, 0, '2024-03-01T15:31:41.579969Z', 4);
-
-INSERT INTO PROJECTAUTHORIZATION (role, project_id, user_name)
-VALUES ('OWNER', 4, 'test_user_3');
-
-INSERT INTO PROJECT (created_at, name, portfolios_created, scenarios_created, topologies_created, updated_at, id)
-VALUES ('2024-03-01T15:31:41.579969Z', 'Test Project 5', 0, 0, 0, '2024-03-01T15:31:41.579969Z', 5);
-
-INSERT INTO PROJECTAUTHORIZATION (role, project_id, user_name)
-VALUES ('OWNER', 5, 'test_user_3');
-
--- Project to delete
-
-INSERT INTO PROJECT (created_at, name, portfolios_created, scenarios_created, topologies_created, updated_at, id)
-VALUES ('2024-03-01T15:31:41.579969Z', 'Test Project Delete', 0, 0, 0, '2024-03-01T15:31:41.579969Z', 6);
-
-INSERT INTO PROJECTAUTHORIZATION (role, project_id, user_name)
-VALUES ('OWNER', 6, 'test_user_1');
-
--- --------------------------------------------------------------------------------
--- PortFolios
--- --------------------------------------------------------------------------------
-
--- Add Portfolio to project 1
-INSERT INTO PORTFOLIO (name, number, project_id, targets, id)
-VALUES ('Test PortFolio Base', 1, 1, '{"metrics": [], "repeats":1}' FORMAT JSON, 1);
-
-INSERT INTO PORTFOLIO (name, number, project_id, targets, id)
-VALUES ('Test PortFolio Delete', 2, 1, '{"metrics": [], "repeats":1}' FORMAT JSON, 2);
-
-INSERT INTO PORTFOLIO (name, number, project_id, targets, id)
-VALUES ('Test PortFolio DeleteEditor', 3, 1, '{"metrics": [], "repeats":1}' FORMAT JSON, 3);
-
-UPDATE Project p
-SET p.portfolios_created = 3, p.updated_at = '2024-03-01T15:31:41.579969Z'
-WHERE p.id = 1;
-
--- --------------------------------------------------------------------------------
--- Topologies
--- --------------------------------------------------------------------------------
-
-INSERT INTO TOPOLOGY (created_at, name, number, project_id, rooms, updated_at, id)
-VALUES ('2024-03-01T15:31:41.579969Z', 'Test Topology testUpdate', 1, 1, '[]' FORMAT JSON, '2024-03-01T15:31:41.579969Z', 1);
-
-INSERT INTO TOPOLOGY (created_at, name, number, project_id, rooms, updated_at, id)
-VALUES ('2024-03-01T15:31:41.579969Z', 'Test Topology testDeleteAsEditor', 2, 1, '[]' FORMAT JSON, '2024-03-01T15:31:41.579969Z', 2);
-
-INSERT INTO TOPOLOGY (created_at, name, number, project_id, rooms, updated_at, id)
-VALUES ('2024-03-01T15:31:41.579969Z', 'Test Topology testDelete', 3, 1, '[]' FORMAT JSON, '2024-03-01T15:31:41.579969Z', 3);
-
-INSERT INTO TOPOLOGY (created_at, name, number, project_id, rooms, updated_at, id)
-VALUES ('2024-03-01T15:31:41.579969Z', 'Test Topology testDeleteUsed', 4, 1, '[]' FORMAT JSON, '2024-03-01T15:31:41.579969Z', 4);
-
-UPDATE Project p
-SET p.topologies_created = 4, p.updated_at = '2024-03-01T15:31:41.579969Z'
-WHERE p.id = 1;
-
--- --------------------------------------------------------------------------------
--- Traces
--- --------------------------------------------------------------------------------
-
-INSERT INTO TRACE (id, name, type)
-VALUES ('bitbrains-small', 'Bitbrains Small', 'small');
-
--- --------------------------------------------------------------------------------
--- Scenario
--- --------------------------------------------------------------------------------
-
-INSERT INTO SCENARIO (name, number, phenomena, portfolio_id, project_id, scheduler_name, topology_id, sampling_fraction, trace_id, id)
-VALUES ('Test Scenario testDelete', 1, '{"failures": false, "interference": false}' FORMAT JSON, 1, 1, 'test', 1, 1.0, 'bitbrains-small', 1);
-
-INSERT INTO SCENARIO (name, number, phenomena, portfolio_id, project_id, scheduler_name, topology_id, sampling_fraction, trace_id, id)
-VALUES ('Test Scenario testDeleteUsed', 2, '{"failures": false, "interference": false}' FORMAT JSON, 1, 1, 'test', 4, 1.0, 'bitbrains-small', 2);
-
-
-UPDATE Project p
-SET p.scenarios_created = 2, p.updated_at = '2024-03-01T15:31:41.579969Z'
-WHERE p.id = 1;
-
--- --------------------------------------------------------------------------------
--- Job
--- --------------------------------------------------------------------------------
-
-INSERT INTO JOB (scenario_id, created_by, created_at, repeats, updated_at, state, runtime, results, id)
-VALUES (1, 'test_user_1', '2024-03-01T15:31:41.579969Z', 1, '2024-03-01T15:31:41.579969Z', 'PENDING', 1, '{}' FORMAT JSON, 1);
-
-INSERT INTO JOB (scenario_id, created_by, created_at, repeats, updated_at, state, runtime, results, id)
-VALUES (1, 'test_user_1', '2024-03-01T15:31:41.579969Z', 1, '2024-03-01T15:31:41.579969Z', 'PENDING', 1, '{}' FORMAT JSON, 2);