Skip to content
This repository was archived by the owner on Oct 14, 2021. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@ package net.adoptopenjdk.api.v3

import net.adoptopenjdk.api.v3.dataSources.APIDataStore
import net.adoptopenjdk.api.v3.routes.AssetsResource
import net.adoptopenjdk.api.v3.routes.BinaryResource
import net.adoptopenjdk.api.v3.routes.packages.BinaryResource
import net.adoptopenjdk.api.v3.routes.V1Route
import net.adoptopenjdk.api.v3.routes.VersionResource
import net.adoptopenjdk.api.v3.routes.info.AvailableReleasesResource
import net.adoptopenjdk.api.v3.routes.info.PlatformsResource
import net.adoptopenjdk.api.v3.routes.info.ReleaseListResource
import net.adoptopenjdk.api.v3.routes.info.VariantsResource
import net.adoptopenjdk.api.v3.routes.packages.InstallerResource
import net.adoptopenjdk.api.v3.routes.stats.DownloadStatsResource
import org.eclipse.microprofile.openapi.annotations.OpenAPIDefinition
import org.eclipse.microprofile.openapi.annotations.info.Info
Expand Down Expand Up @@ -65,7 +66,8 @@ class V3 : Application() {
ReleaseListResource::class.java,
VariantsResource::class.java,
VersionResource::class.java,
DownloadStatsResource::class.java
DownloadStatsResource::class.java,
InstallerResource::class.java
)
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,13 @@
package net.adoptopenjdk.api.v3.routes
package net.adoptopenjdk.api.v3.routes.packages

import net.adoptopenjdk.api.v3.JsonMapper
import net.adoptopenjdk.api.v3.OpenApiDocs
import net.adoptopenjdk.api.v3.dataSources.APIDataStore
import net.adoptopenjdk.api.v3.dataSources.SortOrder
import net.adoptopenjdk.api.v3.filters.BinaryFilter
import net.adoptopenjdk.api.v3.filters.ReleaseFilter
import net.adoptopenjdk.api.v3.models.APIError
import net.adoptopenjdk.api.v3.models.Architecture
import net.adoptopenjdk.api.v3.models.Binary
import net.adoptopenjdk.api.v3.models.HeapSize
import net.adoptopenjdk.api.v3.models.ImageType
import net.adoptopenjdk.api.v3.models.JvmImpl
import net.adoptopenjdk.api.v3.models.OperatingSystem
import net.adoptopenjdk.api.v3.models.Package
import net.adoptopenjdk.api.v3.models.Project
import net.adoptopenjdk.api.v3.models.Release
import net.adoptopenjdk.api.v3.models.ReleaseType
Expand All @@ -25,7 +21,6 @@ import org.eclipse.microprofile.openapi.annotations.responses.APIResponses
import org.eclipse.microprofile.openapi.annotations.tags.Tag
import org.jboss.resteasy.annotations.jaxrs.PathParam
import org.jboss.resteasy.annotations.jaxrs.QueryParam
import java.net.URI
import javax.ws.rs.GET
import javax.ws.rs.HEAD
import javax.ws.rs.HeaderParam
Expand All @@ -39,7 +34,7 @@ import javax.ws.rs.core.Response
@Tag(name = "Binary")
@Path("/v3/binary/")
@Produces(MediaType.APPLICATION_JSON)
class BinaryResource {
class BinaryResource : PackageEndpoint() {

@GET
@HEAD
Expand Down Expand Up @@ -94,68 +89,29 @@ class BinaryResource {
@HeaderParam("User-Agent")
userAgent: String
): Response {
val releases = getReleases(release_name, vendor, os, arch, image_type, jvm_impl, heap_size, project)
return when (request.method) {
"HEAD" -> versionHead(userAgent, release_name, vendor, os, arch, image_type, jvm_impl, heap_size, project)
else -> versionGet(release_name, vendor, os, arch, image_type, jvm_impl, heap_size, project)
}
}

private fun versionGet(
release_name: String?,
vendor: Vendor?,
os: OperatingSystem?,
arch: Architecture?,
image_type: ImageType?,
jvm_impl: JvmImpl?,
heap_size: HeapSize?,
project: Project?
): Response {
return getBinary(release_name, vendor, os, arch, image_type, jvm_impl, heap_size, project) { `package` ->
Response.temporaryRedirect(URI.create(`package`.link)).build()
"HEAD" -> versionHead(userAgent, releases)
else -> formResponse(releases)
}
}

private fun versionHead(
userAgent: String,
release_name: String?,
vendor: Vendor?,
os: OperatingSystem?,
arch: Architecture?,
image_type: ImageType?,
jvm_impl: JvmImpl?,
heap_size: HeapSize?,
project: Project?
releases: List<Release>
): Response {
return if (userAgent.contains("Gradle")) {
getBinary(release_name, vendor, os, arch, image_type, jvm_impl, heap_size, project) { `package` ->
return formResponse(releases) { `package` ->
Response.status(200)
.header("size", `package`.size)
.header("content-disposition", """attachment; filename="${`package`.name}"; filename*=UTF-8''${`package`.name}""")
.build()
}
} else {
versionGet(release_name, vendor, os, arch, image_type, jvm_impl, heap_size, project)
formResponse(releases)
}
}

private fun getBinary(
release_name: String?,
vendor: Vendor?,
os: OperatingSystem?,
arch: Architecture?,
image_type: ImageType?,
jvm_impl: JvmImpl?,
heap_size: HeapSize?,
project: Project?,
createResponse: (net.adoptopenjdk.api.v3.models.Package) -> Response
): Response {
val releaseFilter = ReleaseFilter(releaseName = release_name, vendor = vendor)
val binaryFilter = BinaryFilter(os, arch, image_type, jvm_impl, heap_size, project)
val releases = APIDataStore.getAdoptRepos().getFilteredReleases(releaseFilter, binaryFilter, SortOrder.DESC).toList()

return formResponse(releases, createResponse)
}

@GET
@Path("/latest/{feature_version}/{release_type}/{os}/{arch}/{image_type}/{jvm_impl}/{heap_size}/{vendor}")
@Produces("application/octet-stream")
Expand Down Expand Up @@ -205,53 +161,21 @@ class BinaryResource {
@QueryParam("project")
project: Project?
): Response {
val releaseFilter = ReleaseFilter(releaseType = release_type, featureVersion = version, vendor = vendor)
val binaryFilter = BinaryFilter(os, arch, image_type, jvm_impl, heap_size, project)
val releases = APIDataStore.getAdoptRepos().getFilteredReleases(releaseFilter, binaryFilter, SortOrder.DESC).toList()

val comparator = compareBy<Release> { it.version_data.major }
.thenBy { it.version_data.minor }
.thenBy { it.version_data.security }
.thenBy { it.version_data.pre }
.thenBy { it.version_data.build }
.thenBy { it.version_data.adopt_build_number }
.thenBy { it.version_data.optional }
val releaseList = getRelease(release_type, version, vendor, os, arch, image_type, jvm_impl, heap_size, project)

val release = releases.sortedWith(comparator).lastOrNull()
val release = releaseList.lastOrNull()

return formResponse(if (release == null) emptyList() else listOf(release)) { `package` ->
Response.temporaryRedirect(URI.create(`package`.link)).build()
}
return formResponse(if (release == null) emptyList() else listOf(release))
}

private fun formResponse(releases: List<Release>, createResponse: (net.adoptopenjdk.api.v3.models.Package) -> Response): Response {
if (releases.size == 0) {
return formErrorResponse(Response.Status.NOT_FOUND, "No releases match the request")
} else if (releases.size > 1) {
val versions = releases
.map { it.release_name }
return formErrorResponse(Response.Status.BAD_REQUEST, "Multiple releases match request: $versions")
} else {
val binaries = releases.get(0).binaries
val packages = binaries
.map { it.`package` }
.filterNotNull()

if (packages.size == 0) {
return formErrorResponse(Response.Status.NOT_FOUND, "No binaries match the request")
} else if (packages.size > 1) {
val names = packages.map { it.name }
return formErrorResponse(Response.Status.BAD_REQUEST, "Multiple binaries match request: $names")
} else {
return createResponse(packages.first())
}
}
protected fun formResponse(
releases: List<Release>,
createResponse: (Package) -> Response = redirectToAsset()
): Response {
return formResponse(releases, extractPackage(), createResponse)
}

private fun formErrorResponse(status: Response.Status, message: String): Response {
return Response
.status(status)
.entity(JsonMapper.mapper.writeValueAsString(APIError(message)))
.build()
private fun extractPackage(): (binary: Binary) -> Package {
return { binary -> binary.`package` }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
package net.adoptopenjdk.api.v3.routes.packages

import net.adoptopenjdk.api.v3.OpenApiDocs
import net.adoptopenjdk.api.v3.models.Architecture
import net.adoptopenjdk.api.v3.models.Binary
import net.adoptopenjdk.api.v3.models.HeapSize
import net.adoptopenjdk.api.v3.models.ImageType
import net.adoptopenjdk.api.v3.models.Installer
import net.adoptopenjdk.api.v3.models.JvmImpl
import net.adoptopenjdk.api.v3.models.OperatingSystem
import net.adoptopenjdk.api.v3.models.Project
import net.adoptopenjdk.api.v3.models.Release
import net.adoptopenjdk.api.v3.models.ReleaseType
import net.adoptopenjdk.api.v3.models.Vendor
import org.eclipse.microprofile.openapi.annotations.Operation
import org.eclipse.microprofile.openapi.annotations.enums.SchemaType
import org.eclipse.microprofile.openapi.annotations.media.Schema
import org.eclipse.microprofile.openapi.annotations.parameters.Parameter
import org.eclipse.microprofile.openapi.annotations.responses.APIResponse
import org.eclipse.microprofile.openapi.annotations.responses.APIResponses
import org.eclipse.microprofile.openapi.annotations.tags.Tag
import org.jboss.resteasy.annotations.jaxrs.PathParam
import org.jboss.resteasy.annotations.jaxrs.QueryParam
import javax.ws.rs.GET
import javax.ws.rs.Path
import javax.ws.rs.Produces
import javax.ws.rs.core.MediaType
import javax.ws.rs.core.Response

@Tag(name = "Installer")
@Path("/v3/installer/")
@Produces(MediaType.APPLICATION_JSON)
class InstallerResource : PackageEndpoint() {

@GET
@Path("/version/{release_name}/{os}/{arch}/{image_type}/{jvm_impl}/{heap_size}/{vendor}")
@Produces("application/octet-stream")
@Operation(summary = "Redirects to the installer that matches your current query", description = "Redirects to the installer that matches your current query")
@APIResponses(value = [
APIResponse(responseCode = "307", description = "link to installer that matches your current query"),
APIResponse(responseCode = "400", description = "bad input parameter"),
APIResponse(responseCode = "404", description = "No matching installer found")
]
)
fun returnInstallerByVersion(
@Parameter(name = "os", description = "Operating System", required = true)
@PathParam("os")
os: OperatingSystem?,

@Parameter(name = "arch", description = "Architecture", required = true)
@PathParam("arch")
arch: Architecture?,

@Parameter(name = "release_name", description = OpenApiDocs.RELASE_NAME, required = true,
schema = Schema(defaultValue = "jdk-11.0.6+10", type = SchemaType.STRING)
)
@PathParam("release_name")
release_name: String?,

@Parameter(name = "image_type", description = "Image Type", required = true)
@PathParam("image_type")
image_type: ImageType?,

@Parameter(name = "jvm_impl", description = "JVM Implementation", required = true)
@PathParam("jvm_impl")
jvm_impl: JvmImpl?,

@Parameter(name = "heap_size", description = "Heap Size", required = true)
@PathParam("heap_size")
heap_size: HeapSize?,

@Parameter(name = "vendor", description = OpenApiDocs.VENDOR, required = true)
@PathParam("vendor")
vendor: Vendor?,

@Parameter(name = "project", description = "Project", schema = Schema(defaultValue = "jdk", enumeration = ["jdk", "valhalla", "metropolis", "jfr"], required = false), required = false)
@QueryParam("project")
project: Project?
): Response {
val releases = getReleases(release_name, vendor, os, arch, image_type, jvm_impl, heap_size, project)
return formResponseInstaller(releases)
}

@GET
@Path("/latest/{feature_version}/{release_type}/{os}/{arch}/{image_type}/{jvm_impl}/{heap_size}/{vendor}")
@Produces("application/octet-stream")
@Operation(summary = "Redirects to the installer that matches your current query", description = "Redirects to the installer that matches your current query")
@APIResponses(value = [
APIResponse(responseCode = "307", description = "link to installer that matches your current query"),
APIResponse(responseCode = "400", description = "bad input parameter"),
APIResponse(responseCode = "404", description = "No matching installer found")
]
)
fun returnInstaller(
@Parameter(name = "feature_version", description = OpenApiDocs.FEATURE_RELEASE, required = true,
schema = Schema(defaultValue = "8", type = SchemaType.INTEGER)
)
@PathParam("feature_version")
version: Int?,

@Parameter(name = "release_type", description = OpenApiDocs.RELEASE_TYPE, required = true)
@PathParam("release_type")
release_type: ReleaseType?,

@Parameter(name = "os", description = "Operating System", required = true)
@PathParam("os")
os: OperatingSystem?,

@Parameter(name = "arch", description = "Architecture", required = true)
@PathParam("arch")
arch: Architecture?,

@Parameter(name = "image_type", description = "Image Type", required = true)
@PathParam("image_type")
image_type: ImageType?,

@Parameter(name = "jvm_impl", description = "JVM Implementation", required = true)
@PathParam("jvm_impl")
jvm_impl: JvmImpl?,

@Parameter(name = "heap_size", description = "Heap Size", required = true)
@PathParam("heap_size")
heap_size: HeapSize?,

@Parameter(name = "vendor", description = OpenApiDocs.VENDOR, required = true)
@PathParam("vendor")
vendor: Vendor?,

@Parameter(name = "project", description = "Project", schema = Schema(defaultValue = "jdk", enumeration = ["jdk", "valhalla", "metropolis", "jfr"], required = false), required = false)
@QueryParam("project")
project: Project?
): Response {
val releaseList = getRelease(release_type, version, vendor, os, arch, image_type, jvm_impl, heap_size, project)

val release = releaseList
.lastOrNull { release ->
release.binaries.any { it.installer != null }
}

return formResponseInstaller(if (release == null) emptyList() else listOf(release))
}

private fun formResponseInstaller(releases: List<Release>): Response {
return formResponse(releases, extractInstaller(), redirectToAsset())
}

private fun extractInstaller(): (Binary) -> Installer? {
return { binary -> binary.installer }
}
}
Loading