diff options
| author | Fabian Mastenbroek <mail.fabianm@gmail.com> | 2023-02-03 18:32:34 +0000 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2023-02-03 18:32:34 +0000 |
| commit | bb5e9e7778f6e7cc2161a988fef177d28df8d64f (patch) | |
| tree | 3085bdbc0899c7269e286ce026982c02a3a2864e /opendc-web/opendc-web-server/src/main/kotlin | |
| parent | dd9b7b1e0c59c010fb191a1ea1d805f2748fb216 (diff) | |
| parent | 49b3015a16287bb4486aa64c5c26f05f7c22089c (diff) | |
merge: Clean up web server (#130)
This pull request cleans up the web server to follow Quarkus' best-practices.
## Implementation Notes :hammer_and_pick:
* Migrate to Hypersistence Utils
* Convert web server utils to Java
* Use Panache for entity modeling
* Convert resources to Java
* Remove unnecessary service indirections
## External Dependencies :four_leaf_clover:
* Panache for modeling database entities
* Hypersistence Utils for storing JSON in database
* Mockito for mocking in the web server tests
## Breaking API Changes :warning:
* All implementation is moved to Java for better compatibility with Quarkus.
* Scenarios can now have multiple jobs (e.g., if retried)
Diffstat (limited to 'opendc-web/opendc-web-server/src/main/kotlin')
50 files changed, 0 insertions, 3995 deletions
diff --git a/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/OpenDCApplication.kt b/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/OpenDCApplication.kt deleted file mode 100644 index 1a426095..00000000 --- a/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/OpenDCApplication.kt +++ /dev/null @@ -1,30 +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 - -import javax.ws.rs.core.Application - -/** - * [Application] definition for the OpenDC web API. - */ -class OpenDCApplication : Application() diff --git a/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/model/Job.kt b/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/model/Job.kt deleted file mode 100644 index 84a71acf..00000000 --- a/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/model/Job.kt +++ /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.model - -import org.hibernate.annotations.Type -import org.hibernate.annotations.TypeDef -import org.opendc.web.proto.JobState -import org.opendc.web.server.util.hibernate.json.JsonType -import java.time.Instant -import javax.persistence.Column -import javax.persistence.Entity -import javax.persistence.FetchType -import javax.persistence.GeneratedValue -import javax.persistence.GenerationType -import javax.persistence.Id -import javax.persistence.JoinColumn -import javax.persistence.NamedQueries -import javax.persistence.NamedQuery -import javax.persistence.OneToOne -import javax.persistence.Table - -/** - * A simulation job to be run by the simulator. - */ -@TypeDef(name = "json", typeClass = JsonType::class) -@Entity -@Table(name = "jobs") -@NamedQueries( - value = [ - NamedQuery( - name = "Job.findAll", - query = "SELECT j FROM Job j WHERE j.state = :state" - ), - 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 - """ - ) - ] -) -class Job( - @Id - @GeneratedValue(strategy = GenerationType.AUTO) - val id: Long, - - @Column(name = "created_by", nullable = false, updatable = false) - val createdBy: String, - - @OneToOne(optional = false, mappedBy = "job", fetch = FetchType.EAGER) - @JoinColumn(name = "scenario_id", nullable = false) - val scenario: Scenario, - - @Column(name = "created_at", nullable = false, updatable = false) - val createdAt: Instant, - - /** - * The number of simulation runs to perform. - */ - @Column(nullable = false, updatable = false) - val repeats: Int -) { - /** - * The instant at which the job was updated. - */ - @Column(name = "updated_at", nullable = false) - var updatedAt: Instant = createdAt - - /** - * The state of the job. - */ - @Column(nullable = false) - var state: JobState = JobState.PENDING - - /** - * The runtime of the job (in seconds). - */ - @Column(nullable = false) - var runtime: Int = 0 - - /** - * Experiment results in JSON - */ - @Type(type = "json") - @Column(columnDefinition = "jsonb") - var results: Map<String, Any>? = null - - /** - * Return a string representation of this job. - */ - override fun toString(): String = "Job[id=$id,scenario=${scenario.id},state=$state]" -} diff --git a/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/model/Portfolio.kt b/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/model/Portfolio.kt deleted file mode 100644 index 09437712..00000000 --- a/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/model/Portfolio.kt +++ /dev/null @@ -1,103 +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 org.hibernate.annotations.Type -import org.hibernate.annotations.TypeDef -import org.opendc.web.proto.Targets -import org.opendc.web.server.util.hibernate.json.JsonType -import javax.persistence.CascadeType -import javax.persistence.Column -import javax.persistence.Entity -import javax.persistence.GeneratedValue -import javax.persistence.GenerationType -import javax.persistence.Id -import javax.persistence.Index -import javax.persistence.JoinColumn -import javax.persistence.ManyToOne -import javax.persistence.NamedQueries -import javax.persistence.NamedQuery -import javax.persistence.OneToMany -import javax.persistence.OrderBy -import javax.persistence.Table -import javax.persistence.UniqueConstraint - -/** - * A portfolio is the composition of multiple scenarios. - */ -@TypeDef(name = "json", typeClass = JsonType::class) -@Entity -@Table( - name = "portfolios", - uniqueConstraints = [UniqueConstraint(columnNames = ["project_id", "number"])], - indexes = [Index(name = "fn_portfolios_number", columnList = "project_id, number")] -) -@NamedQueries( - value = [ - NamedQuery( - name = "Portfolio.findAll", - query = "SELECT p FROM Portfolio p WHERE p.project.id = :projectId" - ), - NamedQuery( - name = "Portfolio.findOne", - query = "SELECT p FROM Portfolio p WHERE p.project.id = :projectId AND p.number = :number" - ) - ] -) -class Portfolio( - @Id - @GeneratedValue(strategy = GenerationType.AUTO) - val id: Long, - - /** - * Unique number of the portfolio for the project. - */ - @Column(nullable = false) - val number: Int, - - @Column(nullable = false) - val name: String, - - @ManyToOne(optional = false) - @JoinColumn(name = "project_id", nullable = false) - val project: Project, - - /** - * The portfolio targets (metrics, repetitions). - */ - @Type(type = "json") - @Column(columnDefinition = "jsonb", nullable = false, updatable = false) - val targets: Targets -) { - /** - * The scenarios in this portfolio. - */ - @OneToMany(cascade = [CascadeType.ALL], mappedBy = "portfolio", orphanRemoval = true) - @OrderBy("id ASC") - val scenarios: MutableSet<Scenario> = mutableSetOf() - - /** - * Return a string representation of this portfolio. - */ - override fun toString(): String = "Job[id=$id,name=$name,project=${project.id},targets=$targets]" -} diff --git a/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/model/Project.kt b/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/model/Project.kt deleted file mode 100644 index 41d1a786..00000000 --- a/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/model/Project.kt +++ /dev/null @@ -1,144 +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 java.time.Instant -import javax.persistence.CascadeType -import javax.persistence.Column -import javax.persistence.Entity -import javax.persistence.GeneratedValue -import javax.persistence.GenerationType -import javax.persistence.Id -import javax.persistence.NamedQueries -import javax.persistence.NamedQuery -import javax.persistence.OneToMany -import javax.persistence.OrderBy -import javax.persistence.Table - -/** - * A project in OpenDC encapsulates all the datacenter designs and simulation runs for a set of users. - */ -@Entity -@Table(name = "projects") -@NamedQueries( - value = [ - NamedQuery( - name = "Project.findAll", - query = """ - SELECT a - FROM ProjectAuthorization a - WHERE a.key.userId = :userId - """ - ), - 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 - """ - ) - ] -) -class Project( - @Id - @GeneratedValue(strategy = GenerationType.AUTO) - val id: Long, - - @Column(nullable = false) - var name: String, - - @Column(name = "created_at", nullable = false, updatable = false) - val createdAt: Instant -) { - /** - * The instant at which the project was updated. - */ - @Column(name = "updated_at", nullable = false) - var updatedAt: Instant = createdAt - - /** - * The portfolios belonging to this project. - */ - @OneToMany(cascade = [CascadeType.ALL], mappedBy = "project", orphanRemoval = true) - @OrderBy("id ASC") - val portfolios: MutableSet<Portfolio> = mutableSetOf() - - /** - * The number of portfolios created for this project (including deleted portfolios). - */ - @Column(name = "portfolios_created", nullable = false) - var portfoliosCreated: Int = 0 - - /** - * The topologies belonging to this project. - */ - @OneToMany(cascade = [CascadeType.ALL], mappedBy = "project", orphanRemoval = true) - @OrderBy("id ASC") - val topologies: MutableSet<Topology> = mutableSetOf() - - /** - * The number of topologies created for this project (including deleted topologies). - */ - @Column(name = "topologies_created", nullable = false) - var topologiesCreated: Int = 0 - - /** - * The scenarios belonging to this project. - */ - @OneToMany(mappedBy = "project", orphanRemoval = true) - val scenarios: MutableSet<Scenario> = mutableSetOf() - - /** - * The number of scenarios created for this project (including deleted scenarios). - */ - @Column(name = "scenarios_created", nullable = false) - var scenariosCreated: Int = 0 - - /** - * The users authorized to access the project. - */ - @OneToMany(cascade = [CascadeType.ALL], mappedBy = "project", orphanRemoval = true) - val authorizations: MutableSet<ProjectAuthorization> = mutableSetOf() - - /** - * Return a string representation of this project. - */ - override fun toString(): String = "Project[id=$id,name=$name]" -} diff --git a/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/model/ProjectAuthorization.kt b/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/model/ProjectAuthorization.kt deleted file mode 100644 index 791725cd..00000000 --- a/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/model/ProjectAuthorization.kt +++ /dev/null @@ -1,64 +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 org.opendc.web.proto.user.ProjectRole -import javax.persistence.Column -import javax.persistence.EmbeddedId -import javax.persistence.Entity -import javax.persistence.JoinColumn -import javax.persistence.ManyToOne -import javax.persistence.MapsId -import javax.persistence.Table - -/** - * An authorization for some user to participate in a project. - */ -@Entity -@Table(name = "project_authorizations") -class ProjectAuthorization( - /** - * The user identifier of the authorization. - */ - @EmbeddedId - val key: ProjectAuthorizationKey, - - /** - * The project that the user is authorized to participate in. - */ - @ManyToOne(optional = false) - @MapsId("projectId") - @JoinColumn(name = "project_id", updatable = false, insertable = false, nullable = false) - val project: Project, - - /** - * The role of the user in the project. - */ - @Column(nullable = false) - val role: ProjectRole -) { - /** - * Return a string representation of this project authorization. - */ - override fun toString(): String = "ProjectAuthorization[project=${key.projectId},user=${key.userId},role=$role]" -} diff --git a/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/model/ProjectAuthorizationKey.kt b/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/model/ProjectAuthorizationKey.kt deleted file mode 100644 index 449b6608..00000000 --- a/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/model/ProjectAuthorizationKey.kt +++ /dev/null @@ -1,38 +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 javax.persistence.Column -import javax.persistence.Embeddable - -/** - * Key for representing a [ProjectAuthorization] object. - */ -@Embeddable -data class ProjectAuthorizationKey( - @Column(name = "user_id", nullable = false) - val userId: String, - - @Column(name = "project_id", nullable = false) - val projectId: Long -) : java.io.Serializable diff --git a/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/model/Scenario.kt b/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/model/Scenario.kt deleted file mode 100644 index 62adc9e2..00000000 --- a/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/model/Scenario.kt +++ /dev/null @@ -1,121 +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 org.hibernate.annotations.Type -import org.hibernate.annotations.TypeDef -import org.opendc.web.proto.OperationalPhenomena -import org.opendc.web.server.util.hibernate.json.JsonType -import javax.persistence.CascadeType -import javax.persistence.Column -import javax.persistence.Embedded -import javax.persistence.Entity -import javax.persistence.GeneratedValue -import javax.persistence.GenerationType -import javax.persistence.Id -import javax.persistence.Index -import javax.persistence.JoinColumn -import javax.persistence.ManyToOne -import javax.persistence.NamedQueries -import javax.persistence.NamedQuery -import javax.persistence.OneToOne -import javax.persistence.Table -import javax.persistence.UniqueConstraint - -/** - * A single scenario to be explored by the simulator. - */ -@TypeDef(name = "json", typeClass = JsonType::class) -@Entity -@Table( - name = "scenarios", - uniqueConstraints = [UniqueConstraint(columnNames = ["project_id", "number"])], - indexes = [Index(name = "fn_scenarios_number", columnList = "project_id, number")] -) -@NamedQueries( - value = [ - NamedQuery( - name = "Scenario.findAll", - query = "SELECT s FROM Scenario s WHERE s.project.id = :projectId" - ), - NamedQuery( - name = "Scenario.findAllForPortfolio", - 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.findOne", - query = "SELECT s FROM Scenario s WHERE s.project.id = :projectId AND s.number = :number" - ) - ] -) -class Scenario( - @Id - @GeneratedValue(strategy = GenerationType.AUTO) - val id: Long, - - /** - * Unique number of the scenario for the project. - */ - @Column(nullable = false) - val number: Int, - - @Column(nullable = false, updatable = false) - val name: String, - - @ManyToOne(optional = false) - @JoinColumn(name = "project_id", nullable = false) - val project: Project, - - @ManyToOne(optional = false) - @JoinColumn(name = "portfolio_id", nullable = false) - val portfolio: Portfolio, - - @Embedded - val workload: Workload, - - @ManyToOne(optional = false) - val topology: Topology, - - @Type(type = "json") - @Column(columnDefinition = "jsonb", nullable = false, updatable = false) - val phenomena: OperationalPhenomena, - - @Column(name = "scheduler_name", nullable = false, updatable = false) - val schedulerName: String -) { - /** - * The [Job] associated with the scenario. - */ - @OneToOne(cascade = [CascadeType.ALL]) - lateinit var job: Job - - /** - * Return a string representation of this scenario. - */ - override fun toString(): String = "Scenario[id=$id,name=$name,project=${project.id},portfolio=${portfolio.id}]" -} diff --git a/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/model/Topology.kt b/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/model/Topology.kt deleted file mode 100644 index 26368455..00000000 --- a/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/model/Topology.kt +++ /dev/null @@ -1,103 +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 org.hibernate.annotations.Type -import org.hibernate.annotations.TypeDef -import org.opendc.web.proto.Room -import org.opendc.web.server.util.hibernate.json.JsonType -import java.time.Instant -import javax.persistence.Column -import javax.persistence.Entity -import javax.persistence.GeneratedValue -import javax.persistence.GenerationType -import javax.persistence.Id -import javax.persistence.Index -import javax.persistence.JoinColumn -import javax.persistence.ManyToOne -import javax.persistence.NamedQueries -import javax.persistence.NamedQuery -import javax.persistence.Table -import javax.persistence.UniqueConstraint - -/** - * A datacenter design in OpenDC. - */ -@TypeDef(name = "json", typeClass = JsonType::class) -@Entity -@Table( - name = "topologies", - uniqueConstraints = [UniqueConstraint(columnNames = ["project_id", "number"])], - indexes = [Index(name = "fn_topologies_number", columnList = "project_id, number")] -) -@NamedQueries( - value = [ - NamedQuery( - name = "Topology.findAll", - query = "SELECT t FROM Topology t WHERE t.project.id = :projectId" - ), - NamedQuery( - name = "Topology.findOne", - query = "SELECT t FROM Topology t WHERE t.project.id = :projectId AND t.number = :number" - ) - ] -) -class Topology( - @Id - @GeneratedValue(strategy = GenerationType.AUTO) - val id: Long, - - /** - * Unique number of the topology for the project. - */ - @Column(nullable = false) - val number: Int, - - @Column(nullable = false) - val name: String, - - @ManyToOne(optional = false) - @JoinColumn(name = "project_id", nullable = false) - val project: Project, - - @Column(name = "created_at", nullable = false, updatable = false) - val createdAt: Instant, - - /** - * Datacenter design in JSON - */ - @Type(type = "json") - @Column(columnDefinition = "jsonb", nullable = false) - var rooms: List<Room> = emptyList() -) { - /** - * The instant at which the topology was updated. - */ - @Column(name = "updated_at", nullable = false) - var updatedAt: Instant = createdAt - - /** - * Return a string representation of this topology. - */ - override fun toString(): String = "Topology[id=$id,name=$name,project=${project.id}]" -} diff --git a/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/model/Trace.kt b/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/model/Trace.kt deleted file mode 100644 index 14a88c5a..00000000 --- a/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/model/Trace.kt +++ /dev/null @@ -1,63 +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 javax.persistence.Column -import javax.persistence.Entity -import javax.persistence.Id -import javax.persistence.NamedQueries -import javax.persistence.NamedQuery -import javax.persistence.Table - -/** - * A workload trace available for simulation. - * - * @param id The unique identifier of the trace. - * @param name The name of the trace. - * @param type The type of trace. - */ -@Entity -@Table(name = "traces") -@NamedQueries( - value = [ - NamedQuery( - name = "Trace.findAll", - query = "SELECT t FROM Trace t" - ) - ] -) -class Trace( - @Id - val id: String, - - @Column(nullable = false, updatable = false) - val name: String, - - @Column(nullable = false, updatable = false) - val type: String -) { - /** - * Return a string representation of this trace. - */ - override fun toString(): String = "Trace[id=$id,name=$name,type=$type]" -} diff --git a/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/model/UserAccounting.kt b/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/model/UserAccounting.kt deleted file mode 100644 index 5b813044..00000000 --- a/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/model/UserAccounting.kt +++ /dev/null @@ -1,81 +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 java.time.LocalDate -import javax.persistence.Column -import javax.persistence.Entity -import javax.persistence.Id -import javax.persistence.NamedQueries -import javax.persistence.NamedQuery -import javax.persistence.Table - -/** - * Entity to track the number of simulation minutes used by a user. - */ -@Entity -@Table(name = "user_accounting") -@NamedQueries( - value = [ - 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 - """ - ) - ] -) -class UserAccounting( - @Id - @Column(name = "user_id", nullable = false) - val userId: String, - - /** - * The end of the accounting period. - */ - @Column(name = "period_end", nullable = false) - var periodEnd: LocalDate, - - /** - * The number of simulation seconds to be used per accounting period. - */ - @Column(name = "simulation_time_budget", nullable = false) - var simulationTimeBudget: Int -) { - /** - * 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) - var simulationTime: Int = 0 -} diff --git a/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/model/Workload.kt b/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/model/Workload.kt deleted file mode 100644 index 9c59dc25..00000000 --- a/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/model/Workload.kt +++ /dev/null @@ -1,39 +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 javax.persistence.Column -import javax.persistence.Embeddable -import javax.persistence.ManyToOne - -/** - * Specification of the workload for a [Scenario]. - */ -@Embeddable -class Workload( - @ManyToOne(optional = false) - val trace: Trace, - - @Column(name = "sampling_fraction", nullable = false, updatable = false) - val samplingFraction: Double -) diff --git a/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/repository/JobRepository.kt b/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/repository/JobRepository.kt deleted file mode 100644 index e9bf0af0..00000000 --- a/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/repository/JobRepository.kt +++ /dev/null @@ -1,94 +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.repository - -import org.opendc.web.proto.JobState -import org.opendc.web.server.model.Job -import java.time.Instant -import javax.enterprise.context.ApplicationScoped -import javax.inject.Inject -import javax.persistence.EntityManager - -/** - * A repository to manage [Job] entities. - */ -@ApplicationScoped -class JobRepository @Inject constructor(private val em: EntityManager) { - /** - * Find all jobs currently residing in [state]. - * - * @param state The state in which the jobs should be. - * @return The list of jobs in state [state]. - */ - fun findAll(state: JobState): List<Job> { - return em.createNamedQuery("Job.findAll", Job::class.java) - .setParameter("state", state) - .resultList - } - - /** - * Find the [Job] with the specified [id]. - * - * @param id The unique identifier of the job. - * @return The trace or `null` if it does not exist. - */ - fun findOne(id: Long): Job? { - return em.find(Job::class.java, id) - } - - /** - * Delete the specified [job]. - */ - fun delete(job: Job) { - em.remove(job) - } - - /** - * Save the specified [job] to the database. - */ - fun save(job: Job) { - em.persist(job) - } - - /** - * Atomically update the specified [job]. - * - * @param job The job to update atomically. - * @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 `true` when the update succeeded`, `false` when there was a conflict. - */ - fun updateOne(job: Job, newState: JobState, time: Instant, runtime: Int, results: Map<String, Any>?): Boolean { - val count = em.createNamedQuery("Job.updateOne") - .setParameter("id", job.id) - .setParameter("oldState", job.state) - .setParameter("newState", newState) - .setParameter("updatedAt", Instant.now()) - .setParameter("runtime", runtime) - .setParameter("results", results) - .executeUpdate() - em.refresh(job) - return count > 0 - } -} diff --git a/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/repository/PortfolioRepository.kt b/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/repository/PortfolioRepository.kt deleted file mode 100644 index 77130c15..00000000 --- a/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/repository/PortfolioRepository.kt +++ /dev/null @@ -1,76 +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.repository - -import org.opendc.web.server.model.Portfolio -import javax.enterprise.context.ApplicationScoped -import javax.inject.Inject -import javax.persistence.EntityManager - -/** - * A repository to manage [Portfolio] entities. - */ -@ApplicationScoped -class PortfolioRepository @Inject constructor(private val em: EntityManager) { - /** - * Find all [Portfolio]s that belong to [project][projectId]. - * - * @param projectId The unique identifier of the project. - * @return The list of portfolios that belong to the specified project. - */ - fun findAll(projectId: Long): List<Portfolio> { - return em.createNamedQuery("Portfolio.findAll", Portfolio::class.java) - .setParameter("projectId", projectId) - .resultList - } - - /** - * Find the [Portfolio] with the specified [number] belonging to [project][projectId]. - * - * @param projectId The unique identifier of the project. - * @param number The number of the portfolio. - * @return The portfolio or `null` if it does not exist. - */ - fun findOne(projectId: Long, number: Int): Portfolio? { - return em.createNamedQuery("Portfolio.findOne", Portfolio::class.java) - .setParameter("projectId", projectId) - .setParameter("number", number) - .setMaxResults(1) - .resultList - .firstOrNull() - } - - /** - * Delete the specified [portfolio]. - */ - fun delete(portfolio: Portfolio) { - em.remove(portfolio) - } - - /** - * Save the specified [portfolio] to the database. - */ - fun save(portfolio: Portfolio) { - em.persist(portfolio) - } -} diff --git a/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/repository/ProjectRepository.kt b/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/repository/ProjectRepository.kt deleted file mode 100644 index 519da3de..00000000 --- a/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/repository/ProjectRepository.kt +++ /dev/null @@ -1,157 +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.repository - -import org.opendc.web.server.model.Project -import org.opendc.web.server.model.ProjectAuthorization -import org.opendc.web.server.model.ProjectAuthorizationKey -import java.time.Instant -import javax.enterprise.context.ApplicationScoped -import javax.inject.Inject -import javax.persistence.EntityManager - -/** - * A repository to manage [Project] entities. - */ -@ApplicationScoped -class ProjectRepository @Inject constructor(private val em: EntityManager) { - /** - * List all projects for the user with the specified [userId]. - * - * @param userId The identifier of the user that is requesting the list of projects. - * @return A list of projects that the user has received authorization for. - */ - fun findAll(userId: String): List<ProjectAuthorization> { - return em.createNamedQuery("Project.findAll", ProjectAuthorization::class.java) - .setParameter("userId", userId) - .resultList - } - - /** - * Find the project with [id] for the user with the specified [userId]. - * - * @param userId The identifier of the user that is requesting the list of projects. - * @param id The unique identifier of the project. - * @return The project with the specified identifier or `null` if it does not exist or is not accessible to the - * user with the specified identifier. - */ - fun findOne(userId: String, id: Long): ProjectAuthorization? { - return em.find(ProjectAuthorization::class.java, ProjectAuthorizationKey(userId, id)) - } - - /** - * Delete the specified [project]. - */ - fun delete(project: Project) { - em.remove(project) - } - - /** - * Save the specified [project] to the database. - */ - fun save(project: Project) { - em.persist(project) - } - - /** - * Save the specified [auth] to the database. - */ - fun save(auth: ProjectAuthorization) { - em.persist(auth) - } - - /** - * Allocate the next portfolio number for the specified [project]. - * - * @param project The project to allocate the portfolio number for. - * @param time The time at which the new portfolio is created. - * @param tries The number of times to try to allocate the number before failing. - */ - fun allocatePortfolio(project: Project, time: Instant, tries: Int = 4): Int { - repeat(tries) { - val count = em.createNamedQuery("Project.allocatePortfolio") - .setParameter("id", project.id) - .setParameter("oldState", project.portfoliosCreated) - .setParameter("now", time) - .executeUpdate() - - if (count > 0) { - return project.portfoliosCreated + 1 - } else { - em.refresh(project) - } - } - - throw IllegalStateException("Failed to allocate next portfolio") - } - - /** - * Allocate the next topology number for the specified [project]. - * - * @param project The project to allocate the topology number for. - * @param time The time at which the new topology is created. - * @param tries The number of times to try to allocate the number before failing. - */ - fun allocateTopology(project: Project, time: Instant, tries: Int = 4): Int { - repeat(tries) { - val count = em.createNamedQuery("Project.allocateTopology") - .setParameter("id", project.id) - .setParameter("oldState", project.topologiesCreated) - .setParameter("now", time) - .executeUpdate() - - if (count > 0) { - return project.topologiesCreated + 1 - } else { - em.refresh(project) - } - } - - throw IllegalStateException("Failed to allocate next topology") - } - - /** - * Allocate the next scenario number for the specified [project]. - * - * @param project The project to allocate the scenario number for. - * @param time The time at which the new scenario is created. - * @param tries The number of times to try to allocate the number before failing. - */ - fun allocateScenario(project: Project, time: Instant, tries: Int = 4): Int { - repeat(tries) { - val count = em.createNamedQuery("Project.allocateScenario") - .setParameter("id", project.id) - .setParameter("oldState", project.scenariosCreated) - .setParameter("now", time) - .executeUpdate() - - if (count > 0) { - return project.scenariosCreated + 1 - } else { - em.refresh(project) - } - } - - throw IllegalStateException("Failed to allocate next scenario") - } -} diff --git a/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/repository/ScenarioRepository.kt b/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/repository/ScenarioRepository.kt deleted file mode 100644 index 145db71d..00000000 --- a/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/repository/ScenarioRepository.kt +++ /dev/null @@ -1,90 +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.repository - -import org.opendc.web.server.model.Scenario -import javax.enterprise.context.ApplicationScoped -import javax.inject.Inject -import javax.persistence.EntityManager - -/** - * A repository to manage [Scenario] entities. - */ -@ApplicationScoped -class ScenarioRepository @Inject constructor(private val em: EntityManager) { - /** - * Find all [Scenario]s that belong to [project][projectId]. - * - * @param projectId The unique identifier of the project. - * @return The list of scenarios that belong to the specified project. - */ - fun findAll(projectId: Long): List<Scenario> { - return em.createNamedQuery("Scenario.findAll", Scenario::class.java) - .setParameter("projectId", projectId) - .resultList - } - - /** - * Find all [Scenario]s that belong to [portfolio][number] of [project][projectId]. - * - * @param projectId The unique identifier of the project. - * @param number The number of the portfolio to which the scenarios should belong. - * @return The list of scenarios that belong to the specified portfolio. - */ - fun findAll(projectId: Long, number: Int): List<Scenario> { - return em.createNamedQuery("Scenario.findAllForPortfolio", Scenario::class.java) - .setParameter("projectId", projectId) - .setParameter("number", number) - .resultList - } - - /** - * Find the [Scenario] with the specified [number] belonging to [project][projectId]. - * - * @param projectId The unique identifier of the project. - * @param number The number of the scenario. - * @return The scenario or `null` if it does not exist. - */ - fun findOne(projectId: Long, number: Int): Scenario? { - return em.createNamedQuery("Scenario.findOne", Scenario::class.java) - .setParameter("projectId", projectId) - .setParameter("number", number) - .setMaxResults(1) - .resultList - .firstOrNull() - } - - /** - * Delete the specified [scenario]. - */ - fun delete(scenario: Scenario) { - em.remove(scenario) - } - - /** - * Save the specified [scenario] to the database. - */ - fun save(scenario: Scenario) { - em.persist(scenario) - } -} diff --git a/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/repository/TopologyRepository.kt b/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/repository/TopologyRepository.kt deleted file mode 100644 index e8eadd63..00000000 --- a/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/repository/TopologyRepository.kt +++ /dev/null @@ -1,86 +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.repository - -import org.opendc.web.server.model.Topology -import javax.enterprise.context.ApplicationScoped -import javax.inject.Inject -import javax.persistence.EntityManager - -/** - * A repository to manage [Topology] entities. - */ -@ApplicationScoped -class TopologyRepository @Inject constructor(private val em: EntityManager) { - /** - * Find all [Topology]s that belong to [project][projectId]. - * - * @param projectId The unique identifier of the project. - * @return The list of topologies that belong to the specified project. - */ - fun findAll(projectId: Long): List<Topology> { - return em.createNamedQuery("Topology.findAll", Topology::class.java) - .setParameter("projectId", projectId) - .resultList - } - - /** - * 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. - */ - fun findOne(projectId: Long, number: Int): Topology? { - return em.createNamedQuery("Topology.findOne", Topology::class.java) - .setParameter("projectId", projectId) - .setParameter("number", number) - .setMaxResults(1) - .resultList - .firstOrNull() - } - - /** - * Find the [Topology] with the specified [id]. - * - * @param id Unique identifier of the topology. - * @return The topology or `null` if it does not exist. - */ - fun findOne(id: Long): Topology? { - return em.find(Topology::class.java, id) - } - - /** - * Delete the specified [topology]. - */ - fun delete(topology: Topology) { - em.remove(topology) - } - - /** - * Save the specified [topology] to the database. - */ - fun save(topology: Topology) { - em.persist(topology) - } -} diff --git a/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/repository/TraceRepository.kt b/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/repository/TraceRepository.kt deleted file mode 100644 index f328eea6..00000000 --- a/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/repository/TraceRepository.kt +++ /dev/null @@ -1,53 +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.repository - -import org.opendc.web.server.model.Trace -import javax.enterprise.context.ApplicationScoped -import javax.inject.Inject -import javax.persistence.EntityManager - -/** - * A repository to manage [Trace] entities. - */ -@ApplicationScoped -class TraceRepository @Inject constructor(private val em: EntityManager) { - /** - * Find all workload traces in the database. - * - * @return The list of available workload traces. - */ - fun findAll(): List<Trace> { - return em.createNamedQuery("Trace.findAll", Trace::class.java).resultList - } - - /** - * Find the [Trace] with the specified [id]. - * - * @param id The unique identifier of the trace. - * @return The trace or `null` if it does not exist. - */ - fun findOne(id: String): Trace? { - return em.find(Trace::class.java, id) - } -} diff --git a/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/repository/UserAccountingRepository.kt b/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/repository/UserAccountingRepository.kt deleted file mode 100644 index f0265d3d..00000000 --- a/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/repository/UserAccountingRepository.kt +++ /dev/null @@ -1,88 +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.repository - -import org.opendc.web.server.model.UserAccounting -import java.time.LocalDate -import javax.enterprise.context.ApplicationScoped -import javax.inject.Inject -import javax.persistence.EntityManager - -/** - * A repository to manage [UserAccounting] entities. - */ -@ApplicationScoped -class UserAccountingRepository @Inject constructor(private val em: EntityManager) { - /** - * Find the [UserAccounting] object for the specified [userId]. - * - * @param userId The unique identifier of the user. - * @return The [UserAccounting] object or `null` if it does not exist. - */ - fun findForUser(userId: String): UserAccounting? { - return em.find(UserAccounting::class.java, userId) - } - - /** - * Save the specified [UserAccounting] object to the database. - */ - fun save(accounting: UserAccounting) { - em.persist(accounting) - } - - /** - * Atomically consume the budget for the specified [UserAccounting] object. - * - * @param accounting The [UserAccounting] object to update atomically. - * @param seconds The number of seconds to consume from the user. - * @return `true` when the update succeeded`, `false` when there was a conflict. - */ - fun consumeBudget(accounting: UserAccounting, seconds: Int): Boolean { - val count = em.createNamedQuery("UserAccounting.consumeBudget") - .setParameter("userId", accounting.userId) - .setParameter("periodEnd", accounting.periodEnd) - .setParameter("seconds", seconds) - .executeUpdate() - em.refresh(accounting) - return count > 0 - } - - /** - * Atomically reset the budget for the specified [UserAccounting] object. - * - * @param accounting The [UserAccounting] object to update atomically. - * @param periodEnd The new end period for the budget. - * @param seconds The number of seconds that have already been consumed. - * @return `true` when the update succeeded`, `false` when there was a conflict. - */ - fun resetBudget(accounting: UserAccounting, periodEnd: LocalDate, seconds: Int): Boolean { - val count = em.createNamedQuery("UserAccounting.resetBudget") - .setParameter("userId", accounting.userId) - .setParameter("oldPeriodEnd", accounting.periodEnd) - .setParameter("periodEnd", periodEnd) - .setParameter("seconds", seconds) - .executeUpdate() - em.refresh(accounting) - return count > 0 - } -} diff --git a/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/rest/SchedulerResource.kt b/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/rest/SchedulerResource.kt deleted file mode 100644 index 919b25fc..00000000 --- a/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/rest/SchedulerResource.kt +++ /dev/null @@ -1,48 +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.rest - -import javax.ws.rs.GET -import javax.ws.rs.Path - -/** - * A resource representing the available schedulers that can be used during experiments. - */ -@Path("/schedulers") -class SchedulerResource { - /** - * Obtain all available schedulers. - */ - @GET - fun getAll() = listOf( - "mem", - "mem-inv", - "core-mem", - "core-mem-inv", - "active-servers", - "active-servers-inv", - "provisioned-cores", - "provisioned-cores-inv", - "random" - ) -} diff --git a/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/rest/TraceResource.kt b/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/rest/TraceResource.kt deleted file mode 100644 index a33bd8f1..00000000 --- a/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/rest/TraceResource.kt +++ /dev/null @@ -1,54 +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.rest - -import org.opendc.web.proto.Trace -import org.opendc.web.server.service.TraceService -import javax.inject.Inject -import javax.ws.rs.GET -import javax.ws.rs.Path -import javax.ws.rs.PathParam -import javax.ws.rs.WebApplicationException - -/** - * A resource representing the workload traces available in the OpenDC instance. - */ -@Path("/traces") -class TraceResource @Inject constructor(private val traceService: TraceService) { - /** - * Obtain all available traces. - */ - @GET - fun getAll(): List<Trace> { - return traceService.findAll() - } - - /** - * Obtain trace information by identifier. - */ - @GET - @Path("{id}") - fun get(@PathParam("id") id: String): Trace { - return traceService.findById(id) ?: throw WebApplicationException("Trace not found", 404) - } -} diff --git a/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/rest/error/MissingKotlinParameterExceptionMapper.kt b/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/rest/error/MissingKotlinParameterExceptionMapper.kt deleted file mode 100644 index e50917aa..00000000 --- a/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/rest/error/MissingKotlinParameterExceptionMapper.kt +++ /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. - */ - -package org.opendc.web.server.rest.error - -import com.fasterxml.jackson.module.kotlin.MissingKotlinParameterException -import org.opendc.web.proto.ProtocolError -import javax.ws.rs.core.MediaType -import javax.ws.rs.core.Response -import javax.ws.rs.ext.ExceptionMapper -import javax.ws.rs.ext.Provider - -/** - * An [ExceptionMapper] for [MissingKotlinParameterException] thrown by Jackson. - */ -@Provider -class MissingKotlinParameterExceptionMapper : ExceptionMapper<MissingKotlinParameterException> { - override fun toResponse(exception: MissingKotlinParameterException): Response { - return Response.status(Response.Status.BAD_REQUEST) - .entity(ProtocolError(Response.Status.BAD_REQUEST.statusCode, "Field '${exception.parameter.name}' is missing from body.")) - .type(MediaType.APPLICATION_JSON) - .build() - } -} diff --git a/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/rest/error/WebApplicationExceptionMapper.kt b/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/rest/error/WebApplicationExceptionMapper.kt deleted file mode 100644 index aa046abf..00000000 --- a/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/rest/error/WebApplicationExceptionMapper.kt +++ /dev/null @@ -1,45 +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.rest.error - -import org.opendc.web.proto.ProtocolError -import javax.ws.rs.WebApplicationException -import javax.ws.rs.core.MediaType -import javax.ws.rs.core.Response -import javax.ws.rs.ext.ExceptionMapper -import javax.ws.rs.ext.Provider - -/** - * Helper class to transform a [WebApplicationException] into an JSON error response. - */ -@Provider -class WebApplicationExceptionMapper : ExceptionMapper<WebApplicationException> { - override fun toResponse(exception: WebApplicationException): Response { - val code = exception.response.status - - return Response.status(code) - .entity(ProtocolError(code, exception.message ?: "Unknown error")) - .type(MediaType.APPLICATION_JSON) - .build() - } -} diff --git a/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/rest/runner/JobResource.kt b/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/rest/runner/JobResource.kt deleted file mode 100644 index d0432360..00000000 --- a/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/rest/runner/JobResource.kt +++ /dev/null @@ -1,76 +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.rest.runner - -import org.opendc.web.proto.runner.Job -import org.opendc.web.server.service.JobService -import javax.annotation.security.RolesAllowed -import javax.inject.Inject -import javax.transaction.Transactional -import javax.validation.Valid -import javax.ws.rs.GET -import javax.ws.rs.POST -import javax.ws.rs.Path -import javax.ws.rs.PathParam -import javax.ws.rs.WebApplicationException - -/** - * A resource representing the available simulation jobs. - */ -@Path("/jobs") -@RolesAllowed("runner") -class JobResource @Inject constructor(private val jobService: JobService) { - /** - * Obtain all pending simulation jobs. - */ - @GET - fun queryPending(): List<Job> { - return jobService.queryPending() - } - - /** - * Get a job by identifier. - */ - @GET - @Path("{job}") - fun get(@PathParam("job") id: Long): Job { - return jobService.findById(id) ?: throw WebApplicationException("Job not found", 404) - } - - /** - * Atomically update the state of a job. - */ - @POST - @Path("{job}") - @Transactional - fun update(@PathParam("job") id: Long, @Valid update: Job.Update): Job { - return try { - jobService.updateState(id, update.state, update.runtime, update.results) - ?: throw WebApplicationException("Job not found", 404) - } catch (e: IllegalArgumentException) { - throw WebApplicationException(e, 400) - } catch (e: IllegalStateException) { - throw WebApplicationException(e, 409) - } - } -} diff --git a/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/rest/user/PortfolioResource.kt b/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/rest/user/PortfolioResource.kt deleted file mode 100644 index ebe57ae2..00000000 --- a/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/rest/user/PortfolioResource.kt +++ /dev/null @@ -1,83 +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.rest.user - -import io.quarkus.security.identity.SecurityIdentity -import org.opendc.web.proto.user.Portfolio -import org.opendc.web.server.service.PortfolioService -import javax.annotation.security.RolesAllowed -import javax.inject.Inject -import javax.transaction.Transactional -import javax.validation.Valid -import javax.ws.rs.DELETE -import javax.ws.rs.GET -import javax.ws.rs.POST -import javax.ws.rs.Path -import javax.ws.rs.PathParam -import javax.ws.rs.WebApplicationException - -/** - * A resource representing the portfolios of a project. - */ -@Path("/projects/{project}/portfolios") -@RolesAllowed("openid") -class PortfolioResource @Inject constructor( - private val portfolioService: PortfolioService, - private val identity: SecurityIdentity -) { - /** - * Get all portfolios that belong to the specified project. - */ - @GET - fun getAll(@PathParam("project") projectId: Long): List<Portfolio> { - return portfolioService.findAll(identity.principal.name, projectId) - } - - /** - * Create a portfolio for this project. - */ - @POST - @Transactional - fun create(@PathParam("project") projectId: Long, @Valid request: Portfolio.Create): Portfolio { - return portfolioService.create(identity.principal.name, projectId, request) ?: throw WebApplicationException("Project not found", 404) - } - - /** - * Obtain a portfolio by its identifier. - */ - @GET - @Path("{portfolio}") - fun get(@PathParam("project") projectId: Long, @PathParam("portfolio") number: Int): Portfolio { - return portfolioService.findOne(identity.principal.name, projectId, number) ?: throw WebApplicationException("Portfolio not found", 404) - } - - /** - * Delete a portfolio. - */ - @DELETE - @Path("{portfolio}") - @Transactional - fun delete(@PathParam("project") projectId: Long, @PathParam("portfolio") number: Int): Portfolio { - return portfolioService.delete(identity.principal.name, projectId, number) ?: throw WebApplicationException("Portfolio not found", 404) - } -} diff --git a/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/rest/user/PortfolioScenarioResource.kt b/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/rest/user/PortfolioScenarioResource.kt deleted file mode 100644 index 82f35127..00000000 --- a/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/rest/user/PortfolioScenarioResource.kt +++ /dev/null @@ -1,63 +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.rest.user - -import io.quarkus.security.identity.SecurityIdentity -import org.opendc.web.proto.user.Scenario -import org.opendc.web.server.service.ScenarioService -import javax.annotation.security.RolesAllowed -import javax.inject.Inject -import javax.transaction.Transactional -import javax.validation.Valid -import javax.ws.rs.GET -import javax.ws.rs.POST -import javax.ws.rs.Path -import javax.ws.rs.PathParam -import javax.ws.rs.WebApplicationException - -/** - * A resource representing the scenarios of a portfolio. - */ -@Path("/projects/{project}/portfolios/{portfolio}/scenarios") -@RolesAllowed("openid") -class PortfolioScenarioResource @Inject constructor( - private val scenarioService: ScenarioService, - private val identity: SecurityIdentity -) { - /** - * Get all scenarios that belong to the specified portfolio. - */ - @GET - fun get(@PathParam("project") projectId: Long, @PathParam("portfolio") portfolioNumber: Int): List<Scenario> { - return scenarioService.findAll(identity.principal.name, projectId, portfolioNumber) - } - - /** - * Create a scenario for this portfolio. - */ - @POST - @Transactional - fun create(@PathParam("project") projectId: Long, @PathParam("portfolio") portfolioNumber: Int, @Valid request: Scenario.Create): Scenario { - return scenarioService.create(identity.principal.name, projectId, portfolioNumber, request) ?: throw WebApplicationException("Portfolio not found", 404) - } -} diff --git a/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/rest/user/ProjectResource.kt b/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/rest/user/ProjectResource.kt deleted file mode 100644 index 817f53a5..00000000 --- a/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/rest/user/ProjectResource.kt +++ /dev/null @@ -1,87 +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.rest.user - -import io.quarkus.security.identity.SecurityIdentity -import org.opendc.web.proto.user.Project -import org.opendc.web.server.service.ProjectService -import javax.annotation.security.RolesAllowed -import javax.inject.Inject -import javax.transaction.Transactional -import javax.validation.Valid -import javax.ws.rs.DELETE -import javax.ws.rs.GET -import javax.ws.rs.POST -import javax.ws.rs.Path -import javax.ws.rs.PathParam -import javax.ws.rs.WebApplicationException - -/** - * A resource representing the created projects. - */ -@Path("/projects") -@RolesAllowed("openid") -class ProjectResource @Inject constructor( - private val projectService: ProjectService, - private val identity: SecurityIdentity -) { - /** - * Obtain all the projects of the current user. - */ - @GET - fun getAll(): List<Project> { - return projectService.findWithUser(identity.principal.name) - } - - /** - * Create a new project for the current user. - */ - @POST - @Transactional - fun create(@Valid request: Project.Create): Project { - return projectService.createForUser(identity.principal.name, request.name) - } - - /** - * Obtain a single project by its identifier. - */ - @GET - @Path("{project}") - fun get(@PathParam("project") id: Long): Project { - return projectService.findWithUser(identity.principal.name, id) ?: throw WebApplicationException("Project not found", 404) - } - - /** - * Delete a project. - */ - @DELETE - @Path("{project}") - @Transactional - fun delete(@PathParam("project") id: Long): Project { - try { - return projectService.deleteWithUser(identity.principal.name, id) ?: throw WebApplicationException("Project not found", 404) - } catch (e: IllegalArgumentException) { - throw WebApplicationException(e.message, 403) - } - } -} diff --git a/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/rest/user/ScenarioResource.kt b/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/rest/user/ScenarioResource.kt deleted file mode 100644 index 56bb4290..00000000 --- a/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/rest/user/ScenarioResource.kt +++ /dev/null @@ -1,64 +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.rest.user - -import io.quarkus.security.identity.SecurityIdentity -import org.opendc.web.proto.user.Scenario -import org.opendc.web.server.service.ScenarioService -import javax.annotation.security.RolesAllowed -import javax.inject.Inject -import javax.transaction.Transactional -import javax.ws.rs.DELETE -import javax.ws.rs.GET -import javax.ws.rs.Path -import javax.ws.rs.PathParam -import javax.ws.rs.WebApplicationException - -/** - * A resource representing the scenarios of a portfolio. - */ -@Path("/projects/{project}/scenarios") -@RolesAllowed("openid") -class ScenarioResource @Inject constructor( - private val scenarioService: ScenarioService, - private val identity: SecurityIdentity -) { - /** - * Obtain a scenario by its identifier. - */ - @GET - @Path("{scenario}") - fun get(@PathParam("project") projectId: Long, @PathParam("scenario") number: Int): Scenario { - return scenarioService.findOne(identity.principal.name, projectId, number) ?: throw WebApplicationException("Scenario not found", 404) - } - - /** - * Delete a scenario. - */ - @DELETE - @Path("{scenario}") - @Transactional - fun delete(@PathParam("project") projectId: Long, @PathParam("scenario") number: Int): Scenario { - return scenarioService.delete(identity.principal.name, projectId, number) ?: throw WebApplicationException("Scenario not found", 404) - } -} diff --git a/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/rest/user/TopologyResource.kt b/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/rest/user/TopologyResource.kt deleted file mode 100644 index 8eef66c8..00000000 --- a/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/rest/user/TopologyResource.kt +++ /dev/null @@ -1,94 +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.rest.user - -import io.quarkus.security.identity.SecurityIdentity -import org.opendc.web.proto.user.Topology -import org.opendc.web.server.service.TopologyService -import javax.annotation.security.RolesAllowed -import javax.inject.Inject -import javax.transaction.Transactional -import javax.validation.Valid -import javax.ws.rs.DELETE -import javax.ws.rs.GET -import javax.ws.rs.POST -import javax.ws.rs.PUT -import javax.ws.rs.Path -import javax.ws.rs.PathParam -import javax.ws.rs.WebApplicationException - -/** - * A resource representing the constructed datacenter topologies. - */ -@Path("/projects/{project}/topologies") -@RolesAllowed("openid") -class TopologyResource @Inject constructor( - private val topologyService: TopologyService, - private val identity: SecurityIdentity -) { - /** - * Get all topologies that belong to the specified project. - */ - @GET - fun getAll(@PathParam("project") projectId: Long): List<Topology> { - return topologyService.findAll(identity.principal.name, projectId) - } - - /** - * Create a topology for this project. - */ - @POST - @Transactional - fun create(@PathParam("project") projectId: Long, @Valid request: Topology.Create): Topology { - return topologyService.create(identity.principal.name, projectId, request) ?: throw WebApplicationException("Topology not found", 404) - } - - /** - * Obtain a topology by its number. - */ - @GET - @Path("{topology}") - fun get(@PathParam("project") projectId: Long, @PathParam("topology") number: Int): Topology { - return topologyService.findOne(identity.principal.name, projectId, number) ?: throw WebApplicationException("Topology not found", 404) - } - - /** - * Update the specified topology by its number. - */ - @PUT - @Path("{topology}") - @Transactional - fun update(@PathParam("project") projectId: Long, @PathParam("topology") number: Int, @Valid request: Topology.Update): Topology { - return topologyService.update(identity.principal.name, projectId, number, request) ?: throw WebApplicationException("Topology not found", 404) - } - - /** - * Delete the specified topology. - */ - @Path("{topology}") - @DELETE - @Transactional - fun delete(@PathParam("project") projectId: Long, @PathParam("topology") number: Int): Topology { - return topologyService.delete(identity.principal.name, projectId, number) ?: throw WebApplicationException("Topology not found", 404) - } -} diff --git a/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/rest/user/UserResource.kt b/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/rest/user/UserResource.kt deleted file mode 100644 index d640cc08..00000000 --- a/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/rest/user/UserResource.kt +++ /dev/null @@ -1,45 +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.rest.user - -import io.quarkus.security.identity.SecurityIdentity -import org.opendc.web.proto.user.User -import org.opendc.web.server.service.UserService -import javax.annotation.security.RolesAllowed -import javax.inject.Inject -import javax.ws.rs.GET -import javax.ws.rs.Path - -/** - * A resource representing the active user. - */ -@Path("/users") -@RolesAllowed("openid") -class UserResource @Inject constructor(private val userService: UserService, private val identity: SecurityIdentity) { - /** - * Get the current active user data. - */ - @GET - @Path("me") - fun get(): User = userService.getUser(identity) -} diff --git a/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/service/JobService.kt b/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/service/JobService.kt deleted file mode 100644 index a0ebd4f4..00000000 --- a/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/service/JobService.kt +++ /dev/null @@ -1,97 +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.service - -import org.opendc.web.proto.JobState -import org.opendc.web.proto.runner.Job -import org.opendc.web.server.repository.JobRepository -import java.time.Instant -import javax.enterprise.context.ApplicationScoped -import javax.inject.Inject - -/** - * Service for managing [Job]s. - */ -@ApplicationScoped -class JobService @Inject constructor( - private val repository: JobRepository, - private val accountingService: UserAccountingService -) { - /** - * Query the pending simulation jobs. - */ - fun queryPending(): List<Job> { - return repository.findAll(JobState.PENDING).map { it.toRunnerDto() } - } - - /** - * Find a job by its identifier. - */ - fun findById(id: Long): Job? { - return repository.findOne(id)?.toRunnerDto() - } - - /** - * Atomically update the state of a [Job]. - * - * @param id The identifier of the job. - * @param newState The next state for the job. - * @param runtime The runtime of the job (in seconds). - * @param results The potential results of the job. - */ - fun updateState(id: Long, newState: JobState, runtime: Int, results: Map<String, Any>?): Job? { - val entity = repository.findOne(id) ?: return null - val state = entity.state - if (!state.isTransitionLegal(newState)) { - throw IllegalArgumentException("Invalid transition from $state to $newState") - } - - val now = Instant.now() - var nextState = newState - val consumedBudget = (runtime - entity.runtime).coerceAtLeast(1) - - // Check whether the user still has any simulation budget left - if (accountingService.consumeSimulationBudget(entity.createdBy, consumedBudget) && nextState == JobState.RUNNING) { - nextState = JobState.FAILED // User has consumed all their budget; cancel the job - } - - if (!repository.updateOne(entity, nextState, now, runtime, results)) { - throw IllegalStateException("Conflicting update") - } - - return entity.toRunnerDto() - } - - /** - * Determine whether the transition from [this] to [newState] is legal. - */ - private fun JobState.isTransitionLegal(newState: JobState): Boolean { - // Note that we always allow transitions from the state - return newState == this || when (this) { - JobState.PENDING -> newState == JobState.CLAIMED - JobState.CLAIMED -> newState == JobState.RUNNING || newState == JobState.FAILED - JobState.RUNNING -> newState == JobState.FINISHED || newState == JobState.FAILED - JobState.FINISHED, JobState.FAILED -> false - } - } -} diff --git a/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/service/PortfolioService.kt b/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/service/PortfolioService.kt deleted file mode 100644 index c83b7a54..00000000 --- a/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/service/PortfolioService.kt +++ /dev/null @@ -1,103 +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.service - -import org.opendc.web.proto.user.Portfolio -import org.opendc.web.server.repository.PortfolioRepository -import org.opendc.web.server.repository.ProjectRepository -import java.time.Instant -import javax.enterprise.context.ApplicationScoped -import javax.inject.Inject -import org.opendc.web.server.model.Portfolio as PortfolioEntity - -/** - * Service for managing [Portfolio]s. - */ -@ApplicationScoped -class PortfolioService @Inject constructor( - private val projectRepository: ProjectRepository, - private val portfolioRepository: PortfolioRepository -) { - /** - * List all [Portfolio]s that belong a certain project. - */ - fun findAll(userId: String, projectId: Long): List<Portfolio> { - // User must have access to project - val auth = projectRepository.findOne(userId, projectId) ?: return emptyList() - val project = auth.toUserDto() - return portfolioRepository.findAll(projectId).map { it.toUserDto(project) } - } - - /** - * Find a [Portfolio] with the specified [number] belonging to [project][projectId]. - */ - fun findOne(userId: String, projectId: Long, number: Int): Portfolio? { - // User must have access to project - val auth = projectRepository.findOne(userId, projectId) ?: return null - return portfolioRepository.findOne(projectId, number)?.toUserDto(auth.toUserDto()) - } - - /** - * Delete the portfolio with the specified [number] belonging to [project][projectId]. - */ - fun delete(userId: String, projectId: Long, number: Int): Portfolio? { - // User must have access to project - val auth = projectRepository.findOne(userId, projectId) - - if (auth == null) { - return null - } else if (!auth.role.canEdit) { - throw IllegalStateException("Not permitted to edit project") - } - - val entity = portfolioRepository.findOne(projectId, number) ?: return null - val portfolio = entity.toUserDto(auth.toUserDto()) - portfolioRepository.delete(entity) - return portfolio - } - - /** - * Construct a new [Portfolio] with the specified name. - */ - fun create(userId: String, projectId: Long, request: Portfolio.Create): Portfolio? { - // User must have access to project - val auth = projectRepository.findOne(userId, projectId) - - if (auth == null) { - return null - } else if (!auth.role.canEdit) { - throw IllegalStateException("Not permitted to edit project") - } - - val now = Instant.now() - val project = auth.project - val number = projectRepository.allocatePortfolio(auth.project, now) - - val portfolio = PortfolioEntity(0, number, request.name, project, request.targets) - - project.portfolios.add(portfolio) - portfolioRepository.save(portfolio) - - return portfolio.toUserDto(auth.toUserDto()) - } -} diff --git a/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/service/ProjectService.kt b/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/service/ProjectService.kt deleted file mode 100644 index 2fc5a054..00000000 --- a/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/service/ProjectService.kt +++ /dev/null @@ -1,88 +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.service - -import org.opendc.web.proto.user.ProjectRole -import org.opendc.web.server.model.Project -import org.opendc.web.server.model.ProjectAuthorization -import org.opendc.web.server.model.ProjectAuthorizationKey -import org.opendc.web.server.repository.ProjectRepository -import java.time.Instant -import javax.enterprise.context.ApplicationScoped -import javax.inject.Inject -import org.opendc.web.proto.user.Project as ProjectDto - -/** - * Service for managing [Project]s. - */ -@ApplicationScoped -class ProjectService @Inject constructor(private val repository: ProjectRepository) { - /** - * List all projects for the user with the specified [userId]. - */ - fun findWithUser(userId: String): List<ProjectDto> { - return repository.findAll(userId).map { it.toUserDto() } - } - - /** - * Obtain the project with the specified [id] for the user with the specified [userId]. - */ - fun findWithUser(userId: String, id: Long): ProjectDto? { - return repository.findOne(userId, id)?.toUserDto() - } - - /** - * Create a new [Project] for the user with the specified [userId]. - */ - fun createForUser(userId: String, name: String): ProjectDto { - val now = Instant.now() - val entity = Project(0, name, now) - repository.save(entity) - - val authorization = ProjectAuthorization(ProjectAuthorizationKey(userId, entity.id), entity, ProjectRole.OWNER) - - entity.authorizations.add(authorization) - repository.save(authorization) - - return authorization.toUserDto() - } - - /** - * Delete a project by its identifier. - * - * @param userId The user that invokes the action. - * @param id The identifier of the project. - */ - fun deleteWithUser(userId: String, id: Long): ProjectDto? { - val auth = repository.findOne(userId, id) ?: return null - - if (!auth.role.canDelete) { - throw IllegalArgumentException("Not allowed to delete project") - } - - val now = Instant.now() - val project = auth.toUserDto().copy(updatedAt = now) - repository.delete(auth.project) - return project - } -} diff --git a/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/service/RunnerConversions.kt b/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/service/RunnerConversions.kt deleted file mode 100644 index 465ac2df..00000000 --- a/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/service/RunnerConversions.kt +++ /dev/null @@ -1,69 +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.service - -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 - -/** - * Conversions into DTOs provided to OpenDC runners. - */ - -/** - * Convert a [Topology] into a runner-facing DTO. - */ -internal fun Topology.toRunnerDto(): org.opendc.web.proto.runner.Topology { - return org.opendc.web.proto.runner.Topology(id, number, name, rooms, createdAt, updatedAt) -} - -/** - * Convert a [Portfolio] into a runner-facing DTO. - */ -internal fun Portfolio.toRunnerDto(): org.opendc.web.proto.runner.Portfolio { - return org.opendc.web.proto.runner.Portfolio(id, number, name, targets) -} - -/** - * Convert a [Job] into a runner-facing DTO. - */ -internal fun Job.toRunnerDto(): org.opendc.web.proto.runner.Job { - return org.opendc.web.proto.runner.Job(id, scenario.toRunnerDto(), state, createdAt, updatedAt, runtime, results) -} - -/** - * Convert a [Job] into a runner-facing DTO. - */ -internal fun Scenario.toRunnerDto(): org.opendc.web.proto.runner.Scenario { - return org.opendc.web.proto.runner.Scenario( - id, - number, - portfolio.toRunnerDto(), - name, - workload.toDto(), - topology.toRunnerDto(), - phenomena, - schedulerName - ) -} diff --git a/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/service/ScenarioService.kt b/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/service/ScenarioService.kt deleted file mode 100644 index 083f2451..00000000 --- a/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/service/ScenarioService.kt +++ /dev/null @@ -1,141 +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.service - -import org.opendc.web.proto.JobState -import org.opendc.web.server.model.Job -import org.opendc.web.server.model.Scenario -import org.opendc.web.server.model.Workload -import org.opendc.web.server.repository.PortfolioRepository -import org.opendc.web.server.repository.ProjectRepository -import org.opendc.web.server.repository.ScenarioRepository -import org.opendc.web.server.repository.TopologyRepository -import org.opendc.web.server.repository.TraceRepository -import java.time.Instant -import javax.enterprise.context.ApplicationScoped -import javax.inject.Inject -import org.opendc.web.proto.user.Scenario as ScenarioDto - -/** - * Service for managing [Scenario]s. - */ -@ApplicationScoped -class ScenarioService @Inject constructor( - private val projectRepository: ProjectRepository, - private val portfolioRepository: PortfolioRepository, - private val topologyRepository: TopologyRepository, - private val traceRepository: TraceRepository, - private val scenarioRepository: ScenarioRepository, - private val accountingService: UserAccountingService -) { - /** - * List all [Scenario]s that belong a certain portfolio. - */ - fun findAll(userId: String, projectId: Long, number: Int): List<ScenarioDto> { - // User must have access to project - val auth = projectRepository.findOne(userId, projectId) ?: return emptyList() - val project = auth.toUserDto() - return scenarioRepository.findAll(projectId).map { it.toUserDto(project) } - } - - /** - * Obtain a [Scenario] by identifier. - */ - fun findOne(userId: String, projectId: Long, number: Int): ScenarioDto? { - // User must have access to project - val auth = projectRepository.findOne(userId, projectId) ?: return null - val project = auth.toUserDto() - return scenarioRepository.findOne(projectId, number)?.toUserDto(project) - } - - /** - * Delete the specified scenario. - */ - fun delete(userId: String, projectId: Long, number: Int): ScenarioDto? { - // User must have access to project - val auth = projectRepository.findOne(userId, projectId) - - if (auth == null) { - return null - } else if (!auth.role.canEdit) { - throw IllegalStateException("Not permitted to edit project") - } - - val entity = scenarioRepository.findOne(projectId, number) ?: return null - val scenario = entity.toUserDto(auth.toUserDto()) - scenarioRepository.delete(entity) - return scenario - } - - /** - * Construct a new [Scenario] with the specified data. - */ - fun create(userId: String, projectId: Long, portfolioNumber: Int, request: ScenarioDto.Create): ScenarioDto? { - // User must have access to project - val auth = projectRepository.findOne(userId, projectId) - - if (auth == null) { - return null - } else if (!auth.role.canEdit) { - throw IllegalStateException("Not permitted to edit project") - } - - val portfolio = portfolioRepository.findOne(projectId, portfolioNumber) ?: return null - val topology = requireNotNull( - topologyRepository.findOne( - projectId, - request.topology.toInt() - ) - ) { "Referred topology does not exist" } - val trace = - requireNotNull(traceRepository.findOne(request.workload.trace)) { "Referred trace does not exist" } - - val now = Instant.now() - val project = auth.project - val number = projectRepository.allocateScenario(auth.project, now) - - val scenario = Scenario( - 0, - number, - request.name, - project, - portfolio, - Workload(trace, request.workload.samplingFraction), - topology, - request.phenomena, - request.schedulerName - ) - val job = Job(0, userId, scenario, now, portfolio.targets.repeats) - - // Fail the job if there is not enough budget for the simulation - if (!accountingService.hasSimulationBudget(userId)) { - job.state = JobState.FAILED - } - - scenario.job = job - portfolio.scenarios.add(scenario) - scenarioRepository.save(scenario) - - return scenario.toUserDto(auth.toUserDto()) - } -} diff --git a/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/service/TopologyService.kt b/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/service/TopologyService.kt deleted file mode 100644 index 5c2a457a..00000000 --- a/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/service/TopologyService.kt +++ /dev/null @@ -1,127 +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.service - -import org.opendc.web.proto.user.Topology -import org.opendc.web.server.repository.ProjectRepository -import org.opendc.web.server.repository.TopologyRepository -import java.time.Instant -import javax.enterprise.context.ApplicationScoped -import javax.inject.Inject -import org.opendc.web.server.model.Topology as TopologyEntity - -/** - * Service for managing [Topology]s. - */ -@ApplicationScoped -class TopologyService @Inject constructor( - private val projectRepository: ProjectRepository, - private val topologyRepository: TopologyRepository -) { - /** - * List all [Topology]s that belong a certain project. - */ - fun findAll(userId: String, projectId: Long): List<Topology> { - // User must have access to project - val auth = projectRepository.findOne(userId, projectId) ?: return emptyList() - val project = auth.toUserDto() - return topologyRepository.findAll(projectId).map { it.toUserDto(project) } - } - - /** - * Find the [Topology] with the specified [number] belonging to [project][projectId]. - */ - fun findOne(userId: String, projectId: Long, number: Int): Topology? { - // User must have access to project - val auth = projectRepository.findOne(userId, projectId) ?: return null - return topologyRepository.findOne(projectId, number)?.toUserDto(auth.toUserDto()) - } - - /** - * Delete the [Topology] with the specified [number] belonging to [project][projectId]. - */ - fun delete(userId: String, projectId: Long, number: Int): Topology? { - // User must have access to project - val auth = projectRepository.findOne(userId, projectId) - - if (auth == null) { - return null - } else if (!auth.role.canEdit) { - throw IllegalStateException("Not permitted to edit project") - } - - val entity = topologyRepository.findOne(projectId, number) ?: return null - val now = Instant.now() - val topology = entity.toUserDto(auth.toUserDto()).copy(updatedAt = now) - topologyRepository.delete(entity) - - return topology - } - - /** - * Update a [Topology] with the specified [number] belonging to [project][projectId]. - */ - fun update(userId: String, projectId: Long, number: Int, request: Topology.Update): Topology? { - // User must have access to project - val auth = projectRepository.findOne(userId, projectId) - - if (auth == null) { - return null - } else if (!auth.role.canEdit) { - throw IllegalStateException("Not permitted to edit project") - } - - val entity = topologyRepository.findOne(projectId, number) ?: return null - val now = Instant.now() - - entity.updatedAt = now - entity.rooms = request.rooms - - return entity.toUserDto(auth.toUserDto()) - } - - /** - * Construct a new [Topology] with the specified name. - */ - fun create(userId: String, projectId: Long, request: Topology.Create): Topology? { - // User must have access to project - val auth = projectRepository.findOne(userId, projectId) - - if (auth == null) { - return null - } else if (!auth.role.canEdit) { - throw IllegalStateException("Not permitted to edit project") - } - - val now = Instant.now() - val project = auth.project - val number = projectRepository.allocateTopology(auth.project, now) - - val topology = TopologyEntity(0, number, request.name, project, now, request.rooms) - - project.topologies.add(topology) - topologyRepository.save(topology) - - return topology.toUserDto(auth.toUserDto()) - } -} diff --git a/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/service/TraceService.kt b/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/service/TraceService.kt deleted file mode 100644 index bd14950c..00000000 --- a/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/service/TraceService.kt +++ /dev/null @@ -1,48 +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.service - -import org.opendc.web.proto.Trace -import org.opendc.web.server.repository.TraceRepository -import javax.enterprise.context.ApplicationScoped -import javax.inject.Inject - -/** - * Service for managing [Trace]s. - */ -@ApplicationScoped -class TraceService @Inject constructor(private val repository: TraceRepository) { - /** - * Obtain all available workload traces. - */ - fun findAll(): List<Trace> { - return repository.findAll().map { it.toUserDto() } - } - - /** - * Obtain a workload trace by identifier. - */ - fun findById(id: String): Trace? { - return repository.findOne(id)?.toUserDto() - } -} diff --git a/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/service/UserAccountingService.kt b/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/service/UserAccountingService.kt deleted file mode 100644 index 11066bfb..00000000 --- a/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/service/UserAccountingService.kt +++ /dev/null @@ -1,128 +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.service - -import org.eclipse.microprofile.config.inject.ConfigProperty -import org.opendc.web.server.model.UserAccounting -import org.opendc.web.server.repository.UserAccountingRepository -import java.time.Duration -import java.time.LocalDate -import java.time.temporal.TemporalAdjusters -import javax.enterprise.context.ApplicationScoped -import javax.inject.Inject -import javax.persistence.EntityExistsException -import org.opendc.web.proto.user.UserAccounting as UserAccountingDto - -/** - * Service for tracking the simulation budget of users. - * - * @param repository The [UserAccountingRepository] used to communicate with the database. - * @param simulationBudget The default simulation budget for new users. - */ -@ApplicationScoped -class UserAccountingService @Inject constructor( - private val repository: UserAccountingRepository, - @ConfigProperty(name = "opendc.accounting.simulation-budget", defaultValue = "2000m") - private val simulationBudget: Duration -) { - /** - * Return the [UserAccountingDto] object for the user with the specified [userId]. If the object does not exist in the - * database, a default value is constructed. - */ - fun getAccounting(userId: String): UserAccountingDto { - val accounting = repository.findForUser(userId) - return if (accounting != null) { - UserAccountingDto(accounting.periodEnd, accounting.simulationTime, accounting.simulationTimeBudget) - } else { - UserAccountingDto(getNextAccountingPeriod(), 0, simulationBudget.toSeconds().toInt()) - } - } - - /** - * Determine whether the user with [userId] has any remaining simulation budget. - * - * @param userId The unique identifier of the user. - * @return `true` when the user still has budget left, `false` otherwise. - */ - fun hasSimulationBudget(userId: String): Boolean { - val accounting = repository.findForUser(userId) ?: return true - val today = LocalDate.now() - - // The accounting period must be over or there must be budget remaining. - return !today.isBefore(accounting.periodEnd) || accounting.simulationTimeBudget > accounting.simulationTime - } - - /** - * Consume [seconds] from the simulation budget of the user with [userId]. - * - * @param userId The unique identifier of the user. - * @param seconds The seconds to consume from the simulation budget. - * @param `true` if the user has consumed his full budget or `false` if there is still budget remaining. - */ - fun consumeSimulationBudget(userId: String, seconds: Int): Boolean { - val today = LocalDate.now() - val nextAccountingPeriod = getNextAccountingPeriod(today) - val repository = repository - - // 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 - repeat(3) { - val accounting = repository.findForUser(userId) - - if (accounting == null) { - try { - val newAccounting = UserAccounting(userId, nextAccountingPeriod, simulationBudget.toSeconds().toInt()) - newAccounting.simulationTime = seconds - repository.save(newAccounting) - - return newAccounting.simulationTime >= newAccounting.simulationTimeBudget - } catch (e: EntityExistsException) { - // Conflict due to concurrency; retry - } - } else { - val success = if (!today.isBefore(accounting.periodEnd)) { - repository.resetBudget(accounting, nextAccountingPeriod, seconds) - } else { - repository.consumeBudget(accounting, seconds) - } - - if (success) { - return accounting.simulationTimeBudget <= accounting.simulationTime - } - } - } - - throw IllegalStateException("Failed to allocate consume budget due to conflict") - } - - /** - * Helper method to find next accounting period. - */ - private fun getNextAccountingPeriod(today: LocalDate = LocalDate.now()): LocalDate { - return today.with(TemporalAdjusters.firstDayOfNextMonth()) - } -} diff --git a/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/service/UserConversions.kt b/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/service/UserConversions.kt deleted file mode 100644 index e28d9c0f..00000000 --- a/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/service/UserConversions.kt +++ /dev/null @@ -1,126 +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.service - -import org.opendc.web.proto.user.Project -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 - -/** - * Conversions into DTOs provided to users. - */ - -/** - * Convert a [Trace] entity into a [org.opendc.web.proto.Trace] DTO. - */ -internal fun Trace.toUserDto(): org.opendc.web.proto.Trace { - return org.opendc.web.proto.Trace(id, name, type) -} - -/** - * Convert a [ProjectAuthorization] entity into a [Project] DTO. - */ -internal fun ProjectAuthorization.toUserDto(): Project { - return Project(project.id, project.name, project.createdAt, project.updatedAt, role) -} - -/** - * Convert a [Topology] entity into a [org.opendc.web.proto.user.Topology] DTO. - */ -internal fun Topology.toUserDto(project: Project): org.opendc.web.proto.user.Topology { - return org.opendc.web.proto.user.Topology(id, number, project, name, rooms, createdAt, updatedAt) -} - -/** - * Convert a [Topology] entity into a [org.opendc.web.proto.user.Topology.Summary] DTO. - */ -private fun Topology.toSummaryDto(): org.opendc.web.proto.user.Topology.Summary { - return org.opendc.web.proto.user.Topology.Summary(id, number, name, createdAt, updatedAt) -} - -/** - * Convert a [Portfolio] entity into a [org.opendc.web.proto.user.Portfolio] DTO. - */ -internal fun Portfolio.toUserDto(project: Project): org.opendc.web.proto.user.Portfolio { - return org.opendc.web.proto.user.Portfolio(id, number, project, name, targets, scenarios.map { it.toSummaryDto() }) -} - -/** - * Convert a [Portfolio] entity into a [org.opendc.web.proto.user.Portfolio.Summary] DTO. - */ -private fun Portfolio.toSummaryDto(): org.opendc.web.proto.user.Portfolio.Summary { - return org.opendc.web.proto.user.Portfolio.Summary(id, number, name, targets) -} - -/** - * Convert a [Scenario] entity into a [org.opendc.web.proto.user.Scenario] DTO. - */ -internal fun Scenario.toUserDto(project: Project): org.opendc.web.proto.user.Scenario { - return org.opendc.web.proto.user.Scenario( - id, - number, - project, - portfolio.toSummaryDto(), - name, - workload.toDto(), - topology.toSummaryDto(), - phenomena, - schedulerName, - job.toUserDto() - ) -} - -/** - * Convert a [Scenario] entity into a [org.opendc.web.proto.user.Scenario.Summary] DTO. - */ -private fun Scenario.toSummaryDto(): org.opendc.web.proto.user.Scenario.Summary { - return org.opendc.web.proto.user.Scenario.Summary( - id, - number, - name, - workload.toDto(), - topology.toSummaryDto(), - phenomena, - schedulerName, - job.toUserDto() - ) -} - -/** - * Convert a [Job] entity into a [org.opendc.web.proto.user.Job] DTO. - */ -internal fun Job.toUserDto(): org.opendc.web.proto.user.Job { - return org.opendc.web.proto.user.Job(id, state, createdAt, updatedAt, results) -} - -/** - * Convert a [Workload] entity into a DTO. - */ -internal fun Workload.toDto(): org.opendc.web.proto.Workload { - return org.opendc.web.proto.Workload(trace.toUserDto(), samplingFraction) -} diff --git a/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/service/UserService.kt b/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/service/UserService.kt deleted file mode 100644 index 39352267..00000000 --- a/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/service/UserService.kt +++ /dev/null @@ -1,44 +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.service - -import io.quarkus.security.identity.SecurityIdentity -import org.opendc.web.proto.user.User -import javax.enterprise.context.ApplicationScoped -import javax.inject.Inject - -/** - * Service for managing [User]s. - */ -@ApplicationScoped -class UserService @Inject constructor(private val accounting: UserAccountingService) { - /** - * Obtain the [User] object for the specified [identity]. - */ - fun getUser(identity: SecurityIdentity): User { - val userId = identity.principal.name - val accounting = accounting.getAccounting(userId) - - return User(userId, accounting) - } -} diff --git a/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/service/Utils.kt b/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/service/Utils.kt deleted file mode 100644 index 2d0da3b3..00000000 --- a/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/service/Utils.kt +++ /dev/null @@ -1,40 +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.service - -import org.opendc.web.proto.user.ProjectRole - -/** - * Flag to indicate that the user can edit a project. - */ -internal val ProjectRole.canEdit: Boolean - get() = when (this) { - ProjectRole.OWNER, ProjectRole.EDITOR -> true - ProjectRole.VIEWER -> false - } - -/** - * Flag to indicate that the user can delete a project. - */ -internal val ProjectRole.canDelete: Boolean - get() = this == ProjectRole.OWNER diff --git a/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/util/DevSecurityOverrideFilter.kt b/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/util/DevSecurityOverrideFilter.kt deleted file mode 100644 index 0bdf959a..00000000 --- a/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/util/DevSecurityOverrideFilter.kt +++ /dev/null @@ -1,51 +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 - -import io.quarkus.arc.properties.IfBuildProperty -import java.security.Principal -import javax.ws.rs.container.ContainerRequestContext -import javax.ws.rs.container.ContainerRequestFilter -import javax.ws.rs.container.PreMatching -import javax.ws.rs.core.SecurityContext -import javax.ws.rs.ext.Provider - -/** - * Helper class to disable security for the OpenDC web API when in development mode. - */ -@Provider -@PreMatching -@IfBuildProperty(name = "opendc.security.enabled", stringValue = "false") -class DevSecurityOverrideFilter : ContainerRequestFilter { - override fun filter(requestContext: ContainerRequestContext) { - requestContext.securityContext = object : SecurityContext { - override fun getUserPrincipal(): Principal = Principal { "anon" } - - override fun isSecure(): Boolean = false - - override fun isUserInRole(role: String): Boolean = true - - override fun getAuthenticationScheme(): String = "basic" - } - } -} diff --git a/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/util/KotlinModuleCustomizer.kt b/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/util/KotlinModuleCustomizer.kt deleted file mode 100644 index 8634c8a4..00000000 --- a/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/util/KotlinModuleCustomizer.kt +++ /dev/null @@ -1,38 +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 - -import com.fasterxml.jackson.databind.ObjectMapper -import com.fasterxml.jackson.module.kotlin.KotlinModule -import io.quarkus.jackson.ObjectMapperCustomizer -import javax.inject.Singleton - -/** - * Helper class to register the Kotlin Jackson module. - */ -@Singleton -class KotlinModuleCustomizer : ObjectMapperCustomizer { - override fun customize(objectMapper: ObjectMapper) { - objectMapper.registerModule(KotlinModule.Builder().build()) - } -} diff --git a/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/util/hibernate/json/AbstractJsonSqlTypeDescriptor.kt b/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/util/hibernate/json/AbstractJsonSqlTypeDescriptor.kt deleted file mode 100644 index 9e29b734..00000000 --- a/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/util/hibernate/json/AbstractJsonSqlTypeDescriptor.kt +++ /dev/null @@ -1,74 +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.hibernate.json - -import org.hibernate.type.descriptor.ValueExtractor -import org.hibernate.type.descriptor.WrapperOptions -import org.hibernate.type.descriptor.java.JavaTypeDescriptor -import org.hibernate.type.descriptor.sql.BasicExtractor -import org.hibernate.type.descriptor.sql.SqlTypeDescriptor -import java.sql.CallableStatement -import java.sql.ResultSet -import java.sql.Types - -/** - * Abstract implementation of a [SqlTypeDescriptor] for Hibernate JSON type. - */ -internal abstract class AbstractJsonSqlTypeDescriptor : SqlTypeDescriptor { - - override fun getSqlType(): Int { - return Types.OTHER - } - - override fun canBeRemapped(): Boolean { - return true - } - - override fun <X> getExtractor(typeDescriptor: JavaTypeDescriptor<X>): ValueExtractor<X> { - return object : BasicExtractor<X>(typeDescriptor, this) { - override fun doExtract(rs: ResultSet, name: String, options: WrapperOptions): X { - return typeDescriptor.wrap(extractJson(rs, name), options) - } - - override fun doExtract(statement: CallableStatement, index: Int, options: WrapperOptions): X { - return typeDescriptor.wrap(extractJson(statement, index), options) - } - - override fun doExtract(statement: CallableStatement, name: String, options: WrapperOptions): X { - return typeDescriptor.wrap(extractJson(statement, name), options) - } - } - } - - open fun extractJson(rs: ResultSet, name: String): Any? { - return rs.getObject(name) - } - - open fun extractJson(statement: CallableStatement, index: Int): Any? { - return statement.getObject(index) - } - - open fun extractJson(statement: CallableStatement, name: String): Any? { - return statement.getObject(name) - } -} diff --git a/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/util/hibernate/json/JsonBinarySqlTypeDescriptor.kt b/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/util/hibernate/json/JsonBinarySqlTypeDescriptor.kt deleted file mode 100644 index df6a3013..00000000 --- a/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/util/hibernate/json/JsonBinarySqlTypeDescriptor.kt +++ /dev/null @@ -1,48 +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.hibernate.json - -import com.fasterxml.jackson.databind.JsonNode -import org.hibernate.type.descriptor.ValueBinder -import org.hibernate.type.descriptor.WrapperOptions -import org.hibernate.type.descriptor.java.JavaTypeDescriptor -import org.hibernate.type.descriptor.sql.BasicBinder -import java.sql.CallableStatement -import java.sql.PreparedStatement - -/** - * A [AbstractJsonSqlTypeDescriptor] that stores the JSON as binary (JSONB). - */ -internal object JsonBinarySqlTypeDescriptor : AbstractJsonSqlTypeDescriptor() { - override fun <X> getBinder(typeDescriptor: JavaTypeDescriptor<X>): ValueBinder<X> { - return object : BasicBinder<X>(typeDescriptor, this) { - override fun doBind(st: PreparedStatement, value: X, index: Int, options: WrapperOptions) { - st.setObject(index, typeDescriptor.unwrap(value, JsonNode::class.java, options), sqlType) - } - - override fun doBind(st: CallableStatement, value: X, name: String, options: WrapperOptions) { - st.setObject(name, typeDescriptor.unwrap(value, JsonNode::class.java, options), sqlType) - } - } - } -} diff --git a/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/util/hibernate/json/JsonBytesSqlTypeDescriptor.kt b/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/util/hibernate/json/JsonBytesSqlTypeDescriptor.kt deleted file mode 100644 index 4924f586..00000000 --- a/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/util/hibernate/json/JsonBytesSqlTypeDescriptor.kt +++ /dev/null @@ -1,88 +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.hibernate.json - -import org.hibernate.type.descriptor.ValueBinder -import org.hibernate.type.descriptor.WrapperOptions -import org.hibernate.type.descriptor.java.JavaTypeDescriptor -import org.hibernate.type.descriptor.sql.BasicBinder -import java.io.UnsupportedEncodingException -import java.sql.CallableStatement -import java.sql.PreparedStatement -import java.sql.ResultSet -import java.sql.Types - -/** - * A [AbstractJsonSqlTypeDescriptor] that stores the JSON as UTF-8 encoded bytes. - */ -internal object JsonBytesSqlTypeDescriptor : AbstractJsonSqlTypeDescriptor() { - private val CHARSET = Charsets.UTF_8 - - override fun getSqlType(): Int { - return Types.BINARY - } - - override fun <X> getBinder(javaTypeDescriptor: JavaTypeDescriptor<X>): ValueBinder<X> { - return object : BasicBinder<X>(javaTypeDescriptor, this) { - override fun doBind(st: PreparedStatement, value: X, index: Int, options: WrapperOptions) { - st.setBytes(index, toJsonBytes(javaTypeDescriptor.unwrap(value, String::class.java, options))) - } - - override fun doBind(st: CallableStatement, value: X, name: String, options: WrapperOptions) { - st.setBytes(name, toJsonBytes(javaTypeDescriptor.unwrap(value, String::class.java, options))) - } - } - } - - override fun extractJson(rs: ResultSet, name: String): Any? { - return fromJsonBytes(rs.getBytes(name)) - } - - override fun extractJson(statement: CallableStatement, index: Int): Any? { - return fromJsonBytes(statement.getBytes(index)) - } - - override fun extractJson(statement: CallableStatement, name: String): Any? { - return fromJsonBytes(statement.getBytes(name)) - } - - private fun toJsonBytes(jsonValue: String): ByteArray? { - return try { - jsonValue.toByteArray(CHARSET) - } catch (e: UnsupportedEncodingException) { - throw IllegalStateException(e) - } - } - - private fun fromJsonBytes(jsonBytes: ByteArray?): String? { - return if (jsonBytes == null) { - null - } else { - try { - String(jsonBytes, CHARSET) - } catch (e: UnsupportedEncodingException) { - throw IllegalStateException(e) - } - } - } -} diff --git a/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/util/hibernate/json/JsonSqlTypeDescriptor.kt b/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/util/hibernate/json/JsonSqlTypeDescriptor.kt deleted file mode 100644 index bd22ffbe..00000000 --- a/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/util/hibernate/json/JsonSqlTypeDescriptor.kt +++ /dev/null @@ -1,110 +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.hibernate.json - -import org.hibernate.dialect.H2Dialect -import org.hibernate.dialect.PostgreSQL81Dialect -import org.hibernate.internal.SessionImpl -import org.hibernate.type.descriptor.ValueBinder -import org.hibernate.type.descriptor.ValueExtractor -import org.hibernate.type.descriptor.WrapperOptions -import org.hibernate.type.descriptor.java.JavaTypeDescriptor -import org.hibernate.type.descriptor.sql.BasicBinder -import org.hibernate.type.descriptor.sql.BasicExtractor -import org.hibernate.type.descriptor.sql.SqlTypeDescriptor -import java.sql.CallableStatement -import java.sql.PreparedStatement -import java.sql.ResultSet -import java.sql.Types - -/** - * A [SqlTypeDescriptor] that automatically selects the correct implementation for the database dialect. - */ -internal object JsonSqlTypeDescriptor : SqlTypeDescriptor { - - override fun getSqlType(): Int = Types.OTHER - - override fun canBeRemapped(): Boolean = true - - override fun <X> getExtractor(javaTypeDescriptor: JavaTypeDescriptor<X>): ValueExtractor<X> { - return object : BasicExtractor<X>(javaTypeDescriptor, this) { - private var delegate: AbstractJsonSqlTypeDescriptor? = null - - override fun doExtract(rs: ResultSet, name: String, options: WrapperOptions): X { - return javaTypeDescriptor.wrap(delegate(options).extractJson(rs, name), options) - } - - override fun doExtract(statement: CallableStatement, index: Int, options: WrapperOptions): X { - return javaTypeDescriptor.wrap(delegate(options).extractJson(statement, index), options) - } - - override fun doExtract(statement: CallableStatement, name: String, options: WrapperOptions): X { - return javaTypeDescriptor.wrap(delegate(options).extractJson(statement, name), options) - } - - private fun delegate(options: WrapperOptions): AbstractJsonSqlTypeDescriptor { - var delegate = delegate - if (delegate == null) { - delegate = resolveSqlTypeDescriptor(options) - this.delegate = delegate - } - return delegate - } - } - } - - override fun <X> getBinder(javaTypeDescriptor: JavaTypeDescriptor<X>): ValueBinder<X> { - return object : BasicBinder<X>(javaTypeDescriptor, this) { - private var delegate: ValueBinder<X>? = null - - override fun doBind(st: PreparedStatement, value: X, index: Int, options: WrapperOptions) { - delegate(options).bind(st, value, index, options) - } - - override fun doBind(st: CallableStatement, value: X, name: String, options: WrapperOptions) { - delegate(options).bind(st, value, name, options) - } - - private fun delegate(options: WrapperOptions): ValueBinder<X> { - var delegate = delegate - if (delegate == null) { - delegate = checkNotNull(resolveSqlTypeDescriptor(options).getBinder(javaTypeDescriptor)) - this.delegate = delegate - } - return delegate - } - } - } - - /** - * Helper method to resolve the appropriate [SqlTypeDescriptor] based on the [WrapperOptions]. - */ - private fun resolveSqlTypeDescriptor(options: WrapperOptions): AbstractJsonSqlTypeDescriptor { - val session = options as? SessionImpl - return when (session?.jdbcServices?.dialect) { - is PostgreSQL81Dialect -> JsonBinarySqlTypeDescriptor - is H2Dialect -> JsonBytesSqlTypeDescriptor - else -> JsonStringSqlTypeDescriptor - } - } -} diff --git a/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/util/hibernate/json/JsonStringSqlTypeDescriptor.kt b/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/util/hibernate/json/JsonStringSqlTypeDescriptor.kt deleted file mode 100644 index 6e015762..00000000 --- a/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/util/hibernate/json/JsonStringSqlTypeDescriptor.kt +++ /dev/null @@ -1,63 +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.hibernate.json - -import org.hibernate.type.descriptor.ValueBinder -import org.hibernate.type.descriptor.WrapperOptions -import org.hibernate.type.descriptor.java.JavaTypeDescriptor -import org.hibernate.type.descriptor.sql.BasicBinder -import java.sql.CallableStatement -import java.sql.PreparedStatement -import java.sql.ResultSet -import java.sql.Types - -/** - * A [AbstractJsonSqlTypeDescriptor] that stores the JSON as string (VARCHAR). - */ -internal object JsonStringSqlTypeDescriptor : AbstractJsonSqlTypeDescriptor() { - override fun getSqlType(): Int = Types.VARCHAR - - override fun <X> getBinder(typeDescriptor: JavaTypeDescriptor<X>): ValueBinder<X> { - return object : BasicBinder<X>(typeDescriptor, this) { - override fun doBind(st: PreparedStatement, value: X, index: Int, options: WrapperOptions) { - st.setString(index, typeDescriptor.unwrap(value, String::class.java, options)) - } - - override fun doBind(st: CallableStatement, value: X, name: String, options: WrapperOptions) { - st.setString(name, typeDescriptor.unwrap(value, String::class.java, options)) - } - } - } - - override fun extractJson(rs: ResultSet, name: String): Any? { - return rs.getString(name) - } - - override fun extractJson(statement: CallableStatement, index: Int): Any? { - return statement.getString(index) - } - - override fun extractJson(statement: CallableStatement, name: String): Any? { - return statement.getString(name) - } -} diff --git a/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/util/hibernate/json/JsonType.kt b/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/util/hibernate/json/JsonType.kt deleted file mode 100644 index 9ee21a4c..00000000 --- a/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/util/hibernate/json/JsonType.kt +++ /dev/null @@ -1,48 +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.hibernate.json - -import com.fasterxml.jackson.databind.ObjectMapper -import org.hibernate.type.AbstractSingleColumnStandardBasicType -import org.hibernate.type.BasicType -import org.hibernate.usertype.DynamicParameterizedType -import java.util.Properties -import javax.enterprise.inject.spi.CDI - -/** - * A [BasicType] that contains JSON. - */ -class JsonType(objectMapper: ObjectMapper) : AbstractSingleColumnStandardBasicType<Any>(JsonSqlTypeDescriptor, JsonTypeDescriptor(objectMapper)), DynamicParameterizedType { - /** - * No-arg constructor for Hibernate to instantiate. - */ - constructor() : this(CDI.current().select(ObjectMapper::class.java).get()) - - override fun getName(): String = "json" - - override fun registerUnderJavaType(): Boolean = true - - override fun setParameterValues(parameters: Properties) { - (javaTypeDescriptor as JsonTypeDescriptor).setParameterValues(parameters) - } -} diff --git a/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/util/hibernate/json/JsonTypeDescriptor.kt b/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/util/hibernate/json/JsonTypeDescriptor.kt deleted file mode 100644 index 9407f940..00000000 --- a/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/util/hibernate/json/JsonTypeDescriptor.kt +++ /dev/null @@ -1,150 +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.hibernate.json - -import com.fasterxml.jackson.databind.ObjectMapper -import org.hibernate.HibernateException -import org.hibernate.annotations.common.reflection.XProperty -import org.hibernate.annotations.common.reflection.java.JavaXMember -import org.hibernate.engine.jdbc.BinaryStream -import org.hibernate.engine.jdbc.internal.BinaryStreamImpl -import org.hibernate.type.descriptor.WrapperOptions -import org.hibernate.type.descriptor.java.AbstractTypeDescriptor -import org.hibernate.type.descriptor.java.BlobTypeDescriptor -import org.hibernate.type.descriptor.java.DataHelper -import org.hibernate.type.descriptor.java.MutableMutabilityPlan -import org.hibernate.usertype.DynamicParameterizedType -import java.io.ByteArrayInputStream -import java.io.IOException -import java.io.InputStream -import java.lang.reflect.Type -import java.sql.Blob -import java.sql.SQLException -import java.util.Objects -import java.util.Properties - -/** - * An [AbstractTypeDescriptor] implementation for Hibernate JSON type. - */ -internal class JsonTypeDescriptor(private val objectMapper: ObjectMapper) : AbstractTypeDescriptor<Any>(Any::class.java, JsonMutabilityPlan(objectMapper)), DynamicParameterizedType { - private var type: Type? = null - - override fun setParameterValues(parameters: Properties) { - val xProperty = parameters[DynamicParameterizedType.XPROPERTY] as XProperty - type = if (xProperty is JavaXMember) { - val x = xProperty as JavaXMember - x.javaType - } else { - (parameters[DynamicParameterizedType.PARAMETER_TYPE] as DynamicParameterizedType.ParameterType).returnedClass - } - } - - override fun areEqual(one: Any?, another: Any?): Boolean { - return when { - one === another -> true - one == null || another == null -> false - one is String && another is String -> one == another - one is Collection<*> && another is Collection<*> -> Objects.equals(one, another) - else -> areJsonEqual(one, another) - } - } - - override fun toString(value: Any?): String { - return objectMapper.writeValueAsString(value) - } - - override fun fromString(string: String): Any? { - return objectMapper.readValue(string, objectMapper.typeFactory.constructType(type)) - } - - override fun <X> unwrap(value: Any?, type: Class<X>, options: WrapperOptions): X? { - if (value == null) { - return null - } - - @Suppress("UNCHECKED_CAST") - return when { - String::class.java.isAssignableFrom(type) -> toString(value) - BinaryStream::class.java.isAssignableFrom(type) || ByteArray::class.java.isAssignableFrom(type) -> { - val stringValue = if (value is String) value else toString(value) - BinaryStreamImpl(DataHelper.extractBytes(ByteArrayInputStream(stringValue.toByteArray()))) - } - Blob::class.java.isAssignableFrom(type) -> { - val stringValue = if (value is String) value else toString(value) - BlobTypeDescriptor.INSTANCE.fromString(stringValue) - } - Any::class.java.isAssignableFrom(type) -> toJsonType(value) - else -> throw unknownUnwrap(type) - } as X - } - - override fun <X> wrap(value: X?, options: WrapperOptions): Any? { - if (value == null) { - return null - } - - var blob: Blob? = null - if (Blob::class.java.isAssignableFrom(value.javaClass)) { - blob = options.lobCreator.wrap(value as Blob?) - } else if (ByteArray::class.java.isAssignableFrom(value.javaClass)) { - blob = options.lobCreator.createBlob(value as ByteArray?) - } else if (InputStream::class.java.isAssignableFrom(value.javaClass)) { - val inputStream = value as InputStream - blob = try { - options.lobCreator.createBlob(inputStream, inputStream.available().toLong()) - } catch (e: IOException) { - throw unknownWrap(value.javaClass) - } - } - - val stringValue: String = try { - if (blob != null) String(DataHelper.extractBytes(blob.binaryStream)) else value.toString() - } catch (e: SQLException) { - throw HibernateException("Unable to extract binary stream from Blob", e) - } - - return fromString(stringValue) - } - - private class JsonMutabilityPlan(private val objectMapper: ObjectMapper) : MutableMutabilityPlan<Any>() { - override fun deepCopyNotNull(value: Any): Any { - return objectMapper.treeToValue(objectMapper.valueToTree(value), value.javaClass) - } - } - - private fun readObject(value: String): Any { - return objectMapper.readTree(value) - } - - private fun areJsonEqual(one: Any, another: Any): Boolean { - return readObject(objectMapper.writeValueAsString(one)) == readObject(objectMapper.writeValueAsString(another)) - } - - private fun toJsonType(value: Any?): Any { - return try { - readObject(objectMapper.writeValueAsString(value)) - } catch (e: Exception) { - throw IllegalArgumentException(e) - } - } -} diff --git a/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/util/runner/QuarkusJobManager.kt b/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/util/runner/QuarkusJobManager.kt deleted file mode 100644 index 742a510c..00000000 --- a/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/util/runner/QuarkusJobManager.kt +++ /dev/null @@ -1,68 +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 org.opendc.web.proto.JobState -import org.opendc.web.proto.runner.Job -import org.opendc.web.runner.JobManager -import org.opendc.web.server.service.JobService -import javax.enterprise.context.ApplicationScoped -import javax.inject.Inject -import javax.transaction.Transactional - -/** - * Implementation of [JobManager] that interfaces directly with [JobService] without overhead of the REST API. - */ -@ApplicationScoped -class QuarkusJobManager @Inject constructor(private val service: JobService) : JobManager { - @Transactional - override fun findNext(): Job? { - return service.queryPending().firstOrNull() - } - - @Transactional - override fun claim(id: Long): Boolean { - return try { - service.updateState(id, JobState.CLAIMED, 0, null) - true - } catch (e: IllegalStateException) { - false - } - } - - @Transactional - override fun heartbeat(id: Long, runtime: Int): Boolean { - val res = service.updateState(id, JobState.RUNNING, runtime, null) - return res?.state != JobState.FAILED - } - - @Transactional - override fun fail(id: Long, runtime: Int) { - service.updateState(id, JobState.FAILED, runtime, null) - } - - @Transactional - override fun finish(id: Long, runtime: Int, results: Map<String, Any>) { - service.updateState(id, JobState.FINISHED, runtime, results) - } -} |
