backend migrated to Java 17

This commit is contained in:
2023-07-20 11:00:48 +08:00
parent d9bf885b2d
commit ab81022bce
37 changed files with 955 additions and 375 deletions

View File

@@ -1,6 +1,7 @@
plugins {
alias(catalog.plugins.lombok) apply false
alias(catalog.plugins.wildfly)
id 'java-library'
id 'war'
id 'maven-publish'
}
@@ -8,7 +9,22 @@ plugins {
import net.woggioni.gradle.wildfly.Deploy2WildflyTask
allprojects {
apply plugin: 'net.woggioni.gradle.lombok'
pluginManager.withPlugin('java-library') {
apply plugin: 'net.woggioni.gradle.lombok'
lombok {
version = catalog.versions.lombok.get()
}
tasks.withType(JavaCompile) {
options.release = 17
}
tasks.withType(Test) {
useJUnitPlatform()
}
}
group = 'net.woggioni'
version = getProperty('jpacrepo.version')
@@ -23,24 +39,26 @@ allprojects {
}
mavenCentral()
}
}
dependencies {
implementation platform(group: 'com.lys', name: 'lys-dependencies', version: getProperty('lys.version'))
}
configurations {
deployableArchives {
attributes {
attribute(
LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE,
objects.named(LibraryElements.class, LibraryElements.JAR))
}
lombok {
version = getProperty('lombok.version')
}
tasks.withType(JavaCompile) {
options.release = 17
}
tasks.withType(Test) {
useJUnitPlatform()
transitive = false
canBeConsumed = false
visible = false
canBeResolved = true
}
}
java {
modularity.inferModulePath = true
}
dependencies {
implementation project(':jpacrepo-impl')
@@ -48,19 +66,17 @@ dependencies {
implementation catalog.jwo
implementation catalog.slf4j.api
compileOnly catalog.hibernate.jpamodelgen
compileOnly catalog.jakarta.enterprise.cdi.api
compileOnly catalog.jakarta.servlet.api
compileOnly catalog.jakarta.ejb.api
compileOnly catalog.jakarta.ws.rs.api
compileOnly catalog.jakarta.xml.bind.api
compileOnly catalog.jakarta.enterprise.concurrent.api
providedCompile catalog.jakarta.persistence.api
providedCompile catalog.jakarta.enterprise.cdi.api
providedCompile catalog.jakarta.servlet.api
providedCompile catalog.jakarta.ejb.api
providedCompile catalog.jakarta.ws.rs.api
providedCompile catalog.jakarta.xml.bind.api
providedCompile catalog.jakarta.enterprise.concurrent.api
implementation catalog.commons.compress
implementation catalog.jna
testImplementation catalog.jackson.module.jakarta.xmlbind.annotations
testImplementation catalog.jboss.ejb.client
testImplementation catalog.weld.se.core
@@ -69,10 +85,20 @@ dependencies {
testImplementation catalog.resteasy.client
testImplementation catalog.resteasy.jackson2.provider
testImplementation catalog.jackson.datatype.jsr310
testRuntimeOnly catalog.slf4j.simple
testImplementation catalog.junit.jupiter.api
testImplementation catalog.junit.jupiter.params
testRuntimeOnly catalog.jakartaee.api
testRuntimeOnly catalog.junit.jupiter.engine
testRuntimeOnly group: 'org.glassfish.main.extras', name: 'glassfish-embedded-all', version: '7.0.6'
deployableArchives project
deployableArchives project(':jpacrepo-impl')
deployableArchives project(':jpacrepo-api')
}
File nimDir = project.file('nim')
@@ -83,7 +109,7 @@ Provider<Exec> nimCompileTaskProvider = tasks.register("compileNim", Exec) {
inputs.files(project.fileTree(srcDir), project.fileTree(staticDir))
File outputFile = new File(temporaryDir, "jpacrepo.js")
outputs.file(outputFile)
commandLine 'nim', 'js', "-o:$outputFile", 'src/jpacrepo.nim'
commandLine 'nim', 'js', '-d:release', "-o:$outputFile", 'src/jpacrepo.nim'
workingDir(nimDir)
}
@@ -92,7 +118,30 @@ Provider<War> warTaskProvider = tasks.named('war', War) {
from nimCompileTaskProvider
}
tasks.named('deploy2Wildfly', Deploy2WildflyTask) {
tasks.named('deploy2Wildfly', Deploy2WildflyTask) { d2w ->
d2w.rpcPort = 1234
d2w.rpcUsername = 'woggioni'
// d2w.rpcUsername = 'admin'
d2w.rpcPassword = '123456'
}
File warPath = tasks.named("war", War).get().archiveFile.get().getAsFile()
tasks.named("test", Test) {
jvmArgs = [
'--add-opens', 'java.naming/javax.naming.spi=ALL-UNNAMED',
'--add-opens', 'java.base/java.lang=ALL-UNNAMED',
'--add-opens', 'java.base/java.io=ALL-UNNAMED',
// '--add-opens', 'java.base/java.util=ALL-UNNAMED',
// '--add-opens', 'java.management/javax.management.openmbean=ALL-UNNAMED',
// '--add-opens', 'java.management/javax.management=ALL-UNNAMED',
]
// classpath = configurations.testRuntimeClasspath + sourceSets.test.output
// File warPath = tasks.named("war", War).get().archiveFile.get().getAsFile()
// classpath += warPath
// classpath += tasks.named("war", War).get().outputs.files
inputs.files(configurations.deployableArchives)
systemProperty('jpacrepo.jar.path', configurations.deployableArchives.asPath)
}
publishing {

View File

@@ -1,29 +1,3 @@
net.woggioni.gradle.lombok.version=0.1
net.woggioni.gradle.wildfly.version=0.1
net.woggioni.gradle.envelope.version=1.0-SNAPSHOT
jpacrepo.version=2023.07
jpacrepo.version=2.0-SNAPSHOT
lys.version=0.1-SNAPSHOT
lombok.version=1.18.22
slf4j.version=1.7.32
xz.version=1.9
apache.commons.compress.version=1.21
hibernate.version=5.6.5.Final
jzstd.version=0.1-SNAPSHOT
jwo.version=1.0-SNAPSHOT
jakarta.persistence.version=3.1.0
jakarta.inject.version=2.0.1
jakarta.cdi.version=4.0.1
jakarta.annotation.version=2.1.1
jakarta.ee.version=8.0.0
jaxb.api.version=2.3.1
jboss.ejb.client.version=4.0.43.Final
log4j.version=2.17.2
weld.version=4.0.3.Final
h2.version=2.1.210
resteasy.version=6.0.0.Final
jna.version=5.10.0
junit.jupiter.version=5.8.2
lys.version=2023.07.20

Binary file not shown.

View File

@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.2.1-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

6
gradlew vendored
View File

@@ -205,6 +205,12 @@ set -- \
org.gradle.wrapper.GradleWrapperMain \
"$@"
# Stop when "xargs" is not available.
if ! command -v xargs >/dev/null 2>&1
then
die "xargs is not available"
fi
# Use "xargs" to parse quoted args.
#
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.

14
gradlew.bat vendored
View File

@@ -14,7 +14,7 @@
@rem limitations under the License.
@rem
@if "%DEBUG%" == "" @echo off
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@@ -25,7 +25,7 @@
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
if "%DIRNAME%"=="" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@@ -40,7 +40,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto execute
if %ERRORLEVEL% equ 0 goto execute
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
@@ -75,13 +75,15 @@ set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
if %ERRORLEVEL% equ 0 goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
set EXIT_CODE=%ERRORLEVEL%
if %EXIT_CODE% equ 0 set EXIT_CODE=1
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
exit /b %EXIT_CODE%
:mainEnd
if "%OS%"=="Windows_NT" endlocal

View File

@@ -4,8 +4,14 @@ plugins {
dependencies {
compileOnly catalog.jakarta.xml.bind.api
compileOnly catalog.jakarta.ejb.api
compileOnly catalog.jakarta.persistence.api
compileOnly catalog.jakarta.inject.api
compileOnly catalog.jakarta.ejb.api
compileOnly catalog.jakarta.json.bind.api
compileOnly catalog.jakarta.annotation.api
annotationProcessor catalog.hibernate.jpamodelgen
}
tasks.named(JavaPlugin.COMPILE_JAVA_TASK_NAME, JavaCompile) {

View File

@@ -1,9 +1,12 @@
module net.woggioni.jpacrepo.api {
requires static lombok;
requires static jakarta.xml.bind;
requires static jakarta.ejb;
requires static jakarta.persistence;
requires jakarta.xml.bind;
requires jakarta.ejb;
requires jakarta.persistence;
requires jakarta.annotation;
requires jakarta.json.bind;
exports net.woggioni.jpacrepo.api.model;
exports net.woggioni.jpacrepo.api.service;
exports net.woggioni.jpacrepo.api.wire;
}

View File

@@ -3,6 +3,8 @@ package net.woggioni.jpacrepo.api.model;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import java.io.Serializable;
@RequiredArgsConstructor
public enum CompressionFormat {
XZ("xz"), GZIP("gz"), Z_STANDARD("zst");

View File

@@ -1,27 +1,28 @@
package net.woggioni.jpacrepo.api.model;
import jakarta.persistence.ElementCollection;
import jakarta.persistence.Entity;
import jakarta.json.bind.annotation.JsonbTransient;
import jakarta.json.bind.annotation.JsonbVisibility;
import jakarta.json.bind.config.PropertyVisibilityStrategy;
import jakarta.persistence.Access;
import jakarta.persistence.AccessType;
import jakarta.persistence.ElementCollection;
import jakarta.persistence.EmbeddedId;
import jakarta.persistence.Entity;
import jakarta.persistence.FetchType;
import jakarta.persistence.Index;
import jakarta.persistence.NamedQueries;
import jakarta.persistence.NamedQuery;
import jakarta.persistence.PrePersist;
import jakarta.persistence.PreUpdate;
import jakarta.persistence.Table;
import jakarta.persistence.Index;
import jakarta.persistence.EmbeddedId;
import jakarta.xml.bind.annotation.XmlRootElement;
import jakarta.xml.bind.annotation.XmlAccessType;
import jakarta.xml.bind.annotation.XmlAccessorType;
import jakarta.xml.bind.annotation.XmlRootElement;
import jakarta.xml.bind.annotation.XmlTransient;
import lombok.Data;
import java.time.OffsetDateTime;
import java.io.Serializable;
import java.time.Instant;
import java.util.Set;
@Data
@@ -38,8 +39,8 @@ import java.util.Set;
@Index(columnList = "fileName", unique = true)
})
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class PkgData {
@XmlAccessorType(XmlAccessType.PROPERTY)
public class PkgData implements Serializable {
@EmbeddedId
private PkgId id;
@@ -50,7 +51,7 @@ public class PkgData {
private String url;
private OffsetDateTime buildDate;
private Instant buildDate;
private String packager;
@@ -86,12 +87,14 @@ public class PkgData {
@ElementCollection(fetch = FetchType.EAGER)
private Set<String> backup;
private OffsetDateTime updTimestamp;
@XmlTransient
@JsonbTransient
private Instant updTimestamp;
@PreUpdate
@PrePersist
private void writeTimestamp() {
updTimestamp = OffsetDateTime.now();
updTimestamp = Instant.now();
}
}

View File

@@ -15,7 +15,7 @@ import java.io.Serializable;
@Embeddable
@Access(AccessType.FIELD)
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
@XmlAccessorType(XmlAccessType.PROPERTY)
public class PkgId implements Serializable {
private String name;

View File

@@ -1,8 +1,7 @@
package net.woggioni.jpacrepo.api.service;
import jakarta.ejb.Local;
import net.woggioni.jpacrepo.api.model.CompressionFormat;
import net.woggioni.jpacrepo.api.model.PkgData;
import java.util.List;
@@ -10,5 +9,11 @@ import java.util.List;
@Local
public interface PacmanServiceLocal extends PacmanServiceRemote {
long countResults(String name, String version, String arch);
List<PkgData> searchPackage(String name, String version, String arch, int page, int pageSize, String fileName);
List<PkgData> searchPackage(String name,
String version,
String arch,
CompressionFormat compressionFormat,
String fileName,
int pageNumber,
int pageSize);
}

View File

@@ -1,9 +1,47 @@
package net.woggioni.jpacrepo.api.service;
import jakarta.annotation.Nonnull;
import jakarta.annotation.Nullable;
import jakarta.ejb.Remote;
import net.woggioni.jpacrepo.api.model.CompressionFormat;
import net.woggioni.jpacrepo.api.model.PkgData;
import net.woggioni.jpacrepo.api.model.PkgId;
import net.woggioni.jpacrepo.api.wire.PkgTuple;
import java.util.Collection;
import java.util.List;
import java.util.NavigableMap;
import java.util.Set;
@Remote
public interface PacmanServiceRemote {
void syncDB();
void deletePackage(String filename);
List<String> searchName(@Nonnull String name);
List<PkgData> searchByHash(@Nonnull String hash);
List<PkgData> searchByFileName(@Nonnull String fileName);
List<String> listFiles();
List<String> listHashes();
List<PkgId> searchPkgId(
String name,
String version,
String arch,
CompressionFormat compressionFormat);
@Nullable
PkgData getPackage(PkgId pkgId);
@Nullable
Long getFileSize(String fileName);
Set<String> missingFiles(Collection<String> fileNames);
NavigableMap<PkgId, PkgTuple> getPkgMap();
}

View File

@@ -1,18 +1,22 @@
package net.woggioni.jpacrepo.service.wire;
package net.woggioni.jpacrepo.api.wire;
import jakarta.xml.bind.annotation.XmlAccessType;
import jakarta.xml.bind.annotation.XmlAccessorType;
import jakarta.xml.bind.annotation.XmlElement;
import jakarta.xml.bind.annotation.XmlRootElement;
import net.woggioni.jpacrepo.api.model.PkgData;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
@XmlRootElement
@XmlRootElement(name = "packages")
@XmlAccessorType(XmlAccessType.PROPERTY)
public class PkgDataList extends ArrayList<PkgData> {
public PkgDataList(List<PkgData> l) {
for (PkgData el : l) add(el);
public PkgDataList() {}
public PkgDataList(Collection<PkgData> c) {
super(c);
}
public PkgDataList(PkgData... elements) {
@@ -20,11 +24,11 @@ public class PkgDataList extends ArrayList<PkgData> {
}
@XmlElement(name = "pkgData")
List<PkgData> getItems() {
public List<PkgData> getItems() {
return this;
}
void setItems(List<PkgData> pkgs) {
public void setItems(List<PkgData> pkgs) {
this.clear();
this.addAll(pkgs);
}

View File

@@ -1,4 +1,4 @@
package net.woggioni.jpacrepo.service.wire;
package net.woggioni.jpacrepo.api.wire;
import jakarta.xml.bind.annotation.XmlRootElement;
import lombok.Data;
@@ -8,7 +8,7 @@ import lombok.Data;
public class PkgTuple {
String md5sum;
String filename;
String fileName;
long size;
}

View File

@@ -1,4 +1,4 @@
package net.woggioni.jpacrepo.service.wire;
package net.woggioni.jpacrepo.api.wire;
import jakarta.xml.bind.annotation.XmlElement;
import jakarta.xml.bind.annotation.XmlRootElement;

View File

@@ -0,0 +1,5 @@
<beans xmlns="https://jakarta.ee/xml/ns/jakartaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/beans_4_0.xsd"
version="4.0" bean-discovery-mode="annotated">
</beans>

View File

@@ -0,0 +1,11 @@
plugins {
alias(catalog.plugins.kotlin.multiplatform)
}
kotlin {
js(IR) {
browser {
}
binaries.executable()
}
}

View File

@@ -0,0 +1,70 @@
package net.woggioni.jpacrepo
import org.w3c.dom.Document
import org.w3c.dom.Element
class HtmlBuilder private constructor(private val doc : Document, val el: Element) {
companion object {
fun <T> of(doc : Document, el: Element, cb : HtmlBuilder.(el : Element) -> T) : T {
return HtmlBuilder(doc, el).cb(el)
}
}
private inline fun <T> dfd(
name : String,
attrs : Map<String, String>,
cb : HtmlBuilder.(el : Element) -> T) : T {
val child = doc.createElement(name)
for((key, value) in attrs) {
child.setAttribute(key, value)
}
el.appendChild(child)
return HtmlBuilder(doc, child).cb(child)
}
fun <T> html(attrs : Map<String, String> = emptyMap(),
cb : HtmlBuilder.(el : Element) -> T) : T = dfd("html", attrs, cb)
fun <T> head(attrs : Map<String, String> = emptyMap(),
cb : HtmlBuilder.(el : Element) -> T) : T = dfd("head", attrs, cb)
fun <T> body(attrs : Map<String, String> = emptyMap(),
cb : HtmlBuilder.(el : Element) -> T) : T = dfd("body", attrs, cb)
fun <T> div(attrs : Map<String, String> = emptyMap(),
cb : HtmlBuilder.(el : Element) -> T) : T = dfd("div", attrs, cb)
fun <T> header(attrs : Map<String, String> = emptyMap(),
cb : HtmlBuilder.(el : Element) -> T) : T = dfd("header", attrs, cb)
fun <T> main(attrs : Map<String, String> = emptyMap(),
cb : HtmlBuilder.(el : Element) -> T) : T = dfd("main", attrs, cb)
fun <T> footer(attrs : Map<String, String> = emptyMap(),
cb : HtmlBuilder.(el : Element) -> T) : T = dfd("footer", attrs, cb)
fun <T> a(attrs : Map<String, String> = emptyMap(),
cb : HtmlBuilder.(el : Element) -> T) : T = dfd("a", attrs, cb)
fun <T> meta(attrs : Map<String, String> = emptyMap(),
cb : HtmlBuilder.(el : Element) -> T) : T = dfd("meta", attrs, cb)
fun <T> script(attrs : Map<String, String> = emptyMap(),
cb : HtmlBuilder.(el : Element) -> T) : T = dfd("script", attrs, cb)
fun <T> link(attrs : Map<String, String> = emptyMap(),
cb : HtmlBuilder.(el : Element) -> T) : T = dfd("link", attrs, cb)
fun <T> title(attrs : Map<String, String> = emptyMap(),
cb : HtmlBuilder.(el : Element) -> T) : T = dfd("title", attrs, cb)
fun <T> p(attrs : Map<String, String> = emptyMap(),
cb : HtmlBuilder.(el : Element) -> T) : T = dfd("p", attrs, cb)
fun <T> h1(attrs : Map<String, String> = emptyMap(),
cb : HtmlBuilder.(el : Element) -> T) : T = dfd("h1", attrs, cb)
fun classes(vararg classes : String) {
for(cls in classes) el.classList.add(cls)
}
fun attr(key: String, value : String) {
el.setAttribute(key, value)
}
fun text(txt : String) {
el.textContent = txt
}
}

View File

@@ -0,0 +1,61 @@
package net.woggioni.jpacrepo
import kotlinx.browser.document
import net.woggioni.jpacrepo.Component.container
import org.w3c.dom.HTMLElement
object Component {
val container = document.getElementById("container") as HTMLElement
fun sayHelloViaDom() {
container.textContent = "Hello, DOM! Kotlin is writing…"
}
}
fun main(vararg args: String) {
// println("JavaScript generated through Kotlin")
//
// Component.sayHelloViaDom()
// sayHelloViaJsConsole()
// sayHelloViaInlinedJavaScript()
HtmlBuilder.of(document, document.body as HTMLElement) {
classes("d-flex", "h-100", "text-center", "text-white", "bg-dark")
div {
classes("cover-container", "d-flex", "w-100", "h-100", "p-3", "mx-auto", "flex-column")
}
header {
classes("mb-auto")
}
main {
classes("px-3")
h1 {
text("Cover your page.")
}
p {
classes("lead")
text("Cover is a one-page template for building simple and beautiful home pages. Download, edit the text, and add your own fullscreen background photo to make it your own.")
}
p {
classes("lead")
a {
classes("btn", "btn-lg", "btn-secondary", "fw-bold", "border-white", "bg-white")
text("Learn more")
}
}
}
footer {
classes("mt-auto", "text-white-50")
}
}
}
private fun sayHelloViaJsConsole() {
console.log("Hello from `console.log()`!")
}
private fun sayHelloViaInlinedJavaScript() {
js("document.writeln('Hello, from inlined JavaScript in Kotlin!')")
}

View File

@@ -0,0 +1,10 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM" crossorigin="anonymous"></script>
<script src="jpacrepo-frontend.js" defer="true"></script>
<title>Hello World!</title>
</html>

View File

@@ -23,8 +23,6 @@ import java.nio.file.Files;
import java.nio.file.Path;
import java.text.ParseException;
import java.time.Instant;
import java.time.OffsetDateTime;
import java.time.ZoneOffset;
import java.util.List;
import java.util.Map;
import java.util.Objects;
@@ -110,8 +108,8 @@ public class PkgDataImpl {
data.getId().setName(value.get(0));
break;
case "builddate":
data.setBuildDate(OffsetDateTime.ofInstant(
Instant.ofEpochSecond(Long.parseLong(value.get(0))), ZoneOffset.UTC));
data.setBuildDate(
Instant.ofEpochSecond(Long.parseLong(value.get(0))));
break;
case "license":
data.setLicense(value.get(0));

View File

@@ -129,7 +129,7 @@ proc readTableRow(arch : string, row : Element) : JsonNode =
let version = $row.querySelector("td:nth-child(3) button").textContent
let filename = $row.querySelector("td:nth-child(4) button").textContent
for candidate in pkgMap[arch][pkgname][version]:
if filename == candidate["filename"].getStr:
if filename == candidate["fileName"].getStr:
return candidate
proc createDropdown(parent : Element, data :seq[string], onchange : proc(value : string)) =
@@ -241,7 +241,7 @@ proc newPkgTable(parent: Element, arch: string, searchString : string, addButton
files = f
break
for file in files:
data.add(file["filename"].getStr)
data.add(file["fileName"].getStr)
createDropdown(elem, data, size_change_callback)
"td":
cb:
@@ -309,7 +309,7 @@ htmlTreeappend document.body:
for row in rows:
let cbox = row.querySelector("td:first-child input")
if cbox.checked:
dp.addPkg(readTableRow(selectedArch, row)["filename"].getStr)
dp.addPkg(readTableRow(selectedArch, row)["fileName"].getStr)
oninput:
searchString = $elem.value
updateTable(event)

View File

@@ -1,5 +1,11 @@
pluginManagement {
repositories {
mavenLocal {
content {
includeGroup 'net.woggioni.gradle'
includeGroup 'net.woggioni.gradle.lombok'
}
}
maven {
url = 'https://woggioni.net/mvn/'
content {
@@ -34,4 +40,5 @@ rootProject.name = 'jpacrepo'
include 'jpacrepo-api'
include 'jpacrepo-impl'
include 'jpacrepo-client'
include 'jpacrepo-client'
include 'jpacrepo-frontend'

View File

@@ -14,4 +14,5 @@ open module net.woggioni.jpacrepo {
requires org.slf4j;
requires net.woggioni.jpacrepo.api;
requires org.apache.commons.compress;
}

View File

@@ -1,5 +1,6 @@
package net.woggioni.jpacrepo.factory;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.enterprise.inject.Produces;
import jakarta.enterprise.inject.spi.InjectionPoint;
import net.woggioni.jpacrepo.config.AppConfig;
@@ -7,6 +8,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ApplicationScoped
public class BeanFactory {
@Produces

View File

@@ -8,15 +8,15 @@ import net.woggioni.jpacrepo.config.AppConfig;
import java.util.Properties;
@ApplicationScoped
public class PersistenceUnitFactory {
@Produces
@ApplicationScoped
private EntityManagerFactory createEntityManagerFactory(AppConfig appConfig) {
Properties properties = new Properties();
properties.put("javax.persistence.schema-generation.database.action",
properties.put("jakarta.persistence.schema-generation.database.action",
appConfig.getInitialSchemaAction().getValue());
properties.put("javax.persistence.jtaDataSource", appConfig.getDataSourceJndi());
properties.put("jakarta.persistence.jtaDataSource", appConfig.getDataSourceJndi());
return Persistence.createEntityManagerFactory("jpacrepo_pu", properties);
}
}

View File

@@ -5,99 +5,23 @@ import jakarta.persistence.EntityManager;
import jakarta.persistence.TypedQuery;
import jakarta.persistence.criteria.CriteriaBuilder;
import jakarta.persistence.criteria.CriteriaQuery;
import jakarta.persistence.criteria.Path;
import jakarta.persistence.criteria.Predicate;
import jakarta.persistence.criteria.Root;
import net.woggioni.jpacrepo.api.model.CompressionFormat;
import net.woggioni.jpacrepo.api.model.PkgData;
import net.woggioni.jpacrepo.api.model.PkgData_;
import net.woggioni.jpacrepo.api.model.PkgId;
import net.woggioni.jpacrepo.api.model.PkgId_;
import net.woggioni.jwo.JWO;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Stream;
public class QueryEngine
{
private String entityName;
private String query;
private List<String> where;
public QueryEngine(Class<?> cls) {
query = String.format("SELECT e FROM %s e", cls.getSimpleName());
this.entityName = cls.getSimpleName();
where = new ArrayList<>();
}
public QueryEngine(String entityName) {
query = String.format("SELECT e FROM %s e", entityName);
where = new ArrayList<>();
}
public QueryEngine select(String... fields) {
String[] strarr = new String[fields.length];
for (int i = 0; i < fields.length; i++) {
strarr[i] = "e." + fields[i];
}
query = "SELECT " + String.join(",", strarr) + " FROM " + entityName + " e";
return this;
}
public QueryEngine select() {
query = String.format("SELECT e FROM %s e", entityName);
return this;
}
public QueryEngine where(String field, String operator, String value) {
where.add(String.format("e.%s %s '%s'", field, operator, value));
return this;
}
public String build() {
if (where.isEmpty()) {
return query;
} else {
return query + " WHERE " + String.join(" AND ", where);
}
}
public static List<PkgData> searchPackage(
EntityManager em, String name, String version, String arch, int pageNumber, int pageSize, String fileName) {
CriteriaBuilder builder;
CriteriaQuery<PkgData> criteriaQuery;
Root<PkgData> entity;
builder = em.getCriteriaBuilder();
criteriaQuery = builder.createQuery(PkgData.class);
entity = criteriaQuery.from(PkgData.class);
Predicate finalPredicate = null, p;
if (name != null && !name.isEmpty()) {
p = builder.equal(entity.get("name").get("id"), name);
finalPredicate = p;
}
if (version != null && !version.isEmpty()) {
p = builder.equal(entity.get("version"), version);
finalPredicate = finalPredicate != null ? builder.and(finalPredicate, p) : p;
}
if (arch != null && !arch.isEmpty()) {
p = builder.equal(entity.get("arch"), arch);
finalPredicate = finalPredicate != null ? builder.and(finalPredicate, p) : p;
}
if (fileName != null && !fileName.isEmpty()) {
p = builder.equal(entity.get("fileName"), fileName);
finalPredicate = finalPredicate != null ? builder.and(finalPredicate, p) : p;
}
if (finalPredicate != null) {
criteriaQuery.select(entity).where(finalPredicate).orderBy(builder.asc(entity.get("fileName")));
} else {
criteriaQuery.select(entity).orderBy(builder.asc(entity.get("fileName")));
}
TypedQuery<PkgData> query = em.createQuery(criteriaQuery);
if (pageNumber >= 0) {
query.setFirstResult(pageNumber * pageSize);
}
if (pageSize > 0) {
query.setMaxResults(pageSize);
}
return query.getResultList();
}
public static long countResults(EntityManager em, String name, String version, String arch) {
CriteriaBuilder builder;

View File

@@ -1,5 +1,7 @@
package net.woggioni.jpacrepo.service;
import jakarta.annotation.Nonnull;
import jakarta.annotation.Nullable;
import jakarta.annotation.Resource;
import jakarta.ejb.Asynchronous;
import jakarta.ejb.ConcurrencyManagement;
@@ -9,38 +11,45 @@ import jakarta.ejb.Lock;
import jakarta.ejb.LockType;
import jakarta.ejb.Remote;
import jakarta.ejb.Schedule;
import jakarta.ejb.Startup;
import jakarta.ejb.Singleton;
import jakarta.ejb.TransactionAttribute;
import jakarta.ejb.TransactionAttributeType;
import jakarta.ejb.TransactionManagement;
import jakarta.ejb.TransactionManagementType;
import jakarta.enterprise.concurrent.ManagedExecutorService;
import jakarta.inject.Inject;
import jakarta.inject.Singleton;
import jakarta.persistence.EntityManager;
import jakarta.persistence.EntityManagerFactory;
import jakarta.persistence.TypedQuery;
import lombok.SneakyThrows;
import net.woggioni.jpacrepo.api.model.CompressionFormat;
import net.woggioni.jpacrepo.api.model.PkgData;
import net.woggioni.jpacrepo.api.model.PkgId;
import net.woggioni.jpacrepo.api.service.PacmanServiceLocal;
import net.woggioni.jpacrepo.api.service.PacmanServiceRemote;
import net.woggioni.jpacrepo.config.AppConfig;
import net.woggioni.jpacrepo.impl.model.CompressionFormatImpl;
import net.woggioni.jpacrepo.impl.model.PkgDataImpl;
import net.woggioni.jpacrepo.persistence.QueryEngine;
import net.woggioni.jpacrepo.service.jpa.Queries;
import net.woggioni.jpacrepo.api.wire.PkgTuple;
import net.woggioni.jpacrepo.version.PkgIdComparator;
import net.woggioni.jwo.CollectionUtils;
import net.woggioni.jwo.Con;
import net.woggioni.jwo.JWO;
import net.woggioni.jwo.Sup;
import net.woggioni.jwo.Tuple2;
import org.slf4j.Logger;
import java.nio.file.Files;
import java.nio.file.Path;
import java.time.OffsetDateTime;
import java.util.Calendar;
import java.util.Date;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.NavigableMap;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.CompletionService;
import java.util.concurrent.ExecutionException;
@@ -48,8 +57,8 @@ import java.util.concurrent.ExecutorCompletionService;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@Startup
@Singleton
@Lock(LockType.READ)
@TransactionManagement(TransactionManagementType.CONTAINER)
@@ -69,10 +78,6 @@ public class PacmanServiceEJB implements PacmanServiceLocal {
@Resource(name = "DefaultManagedExecutorService")
private ManagedExecutorService executor;
private final static String nameQuery = "SELECT pname FROM PkgName pname WHERE id = :name";
private final static String hashQuery = "SELECT pdata FROM PkgData pdata WHERE md5sum = :md5sum";
private final static String hashQueryCount = "SELECT count(pdata) FROM PkgData pdata WHERE md5sum = :md5sum";
private void deletePkgData(EntityManager em, PkgData pkgData) {
em.remove(pkgData);
}
@@ -88,7 +93,7 @@ public class PacmanServiceEJB implements PacmanServiceLocal {
logger.info("Starting repository cleanup");
//Removes from DB the packages that have been deleted from filesystem
logger.info("Searching for packages that are no more in the filesystem");
List<String> resultList = em.createQuery("SELECT p.fileName FROM PkgData p", String.class)
List<String> resultList = Queries.listAllPackageFiles(em)
.getResultList();
logger.info("Got list of filenames from db");
Set<String> knownPkg = resultList.stream().filter(fileName -> {
@@ -96,9 +101,9 @@ public class PacmanServiceEJB implements PacmanServiceLocal {
boolean result = Files.exists(file);
if (!result) {
logger.info("Removing package {} which was not found in filesystem", file.getFileName());
em.createQuery("SELECT p FROM PkgData p WHERE p.fileName = :fileName", PkgData.class)
.setParameter("fileName", file.getFileName().toString())
.getResultList().forEach(pkgData -> deletePkgData(em, pkgData));
Queries.getPackageByFileName(em, file.getFileName().toString())
.getResultList()
.forEach(pkgData -> deletePkgData(em, pkgData));
}
return result;
}).collect(Collectors.toUnmodifiableSet());
@@ -106,28 +111,32 @@ public class PacmanServiceEJB implements PacmanServiceLocal {
CompletionService<PkgData> completionService = new ExecutorCompletionService<>(executor);
final Set<Future<PkgData>> inProgress = new HashSet<>();
final int maxInProgress = Runtime.getRuntime().availableProcessors() * 5;
Con<Boolean> persistPackages = (Boolean drain) -> {
while ((drain && inProgress.size() > 0) || inProgress.size() > maxInProgress) {
Future<PkgData> future = completionService.poll(1, TimeUnit.SECONDS);
inProgress.remove(future);
PkgData pkgData;
try {
pkgData = future.get();
} catch (ExecutionException ee) {
throw ee.getCause();
}
persistPackage(em, pkgData);
}
};
Files.list(ctx.getRepoFolder()).filter((Path file) -> {
Sup<Stream<Path>> fileListStreamSupplier = () -> Files.list(ctx.getRepoFolder()).filter((Path file) -> {
String name = file.getFileName().toString();
return name.endsWith(".pkg.tar.xz") || name.endsWith(".pkg.tar.zst") || name.endsWith(".pkg.tar.gz");
}).forEach((Con<Path>) file -> {
});
long[] count = new long[] {0};
long totalPackages = fileListStreamSupplier.get().count();
Con<Boolean> persistPackages = (Boolean drain) -> {
while ((drain && inProgress.size() > 0) || inProgress.size() > maxInProgress) {
Optional.ofNullable(completionService.poll(1, TimeUnit.SECONDS))
.ifPresent((Con<Future<PkgData>>) future -> {
inProgress.remove(future);
PkgData pkgData;
try {
pkgData = future.get();
} catch (ExecutionException ee) {
throw ee.getCause();
}
persistPackage(em, pkgData, ++count[0], totalPackages);
});
}
};
fileListStreamSupplier.get().forEach((Con<Path>) file -> {
if (!knownPkg.contains(file.getFileName().toString()) || ((Sup<Boolean>) () -> {
TypedQuery<Date> query = em.createQuery("SELECT p.updTimestamp FROM PkgData p WHERE filename = :filename", Date.class);
query.setParameter("filename", file.getFileName().toString());
Date result = query.getSingleResult();
return Files.getLastModifiedTime(file).toMillis() > result.getTime();
Instant result = Queries.getUpdateTimestampByFileName(em, file.getFileName().toString()).getSingleResult();
return Files.getLastModifiedTime(file).toMillis() > result.toEpochMilli();
}).get()) {
inProgress.add(completionService.submit(() -> {
try {
@@ -150,16 +159,13 @@ public class PacmanServiceEJB implements PacmanServiceLocal {
}
}
private void persistPackage(EntityManager em, PkgData pkgData) {
TypedQuery<Long> hquery = em.createQuery(hashQueryCount, Long.class);
hquery.setParameter("md5sum", pkgData.getMd5sum());
if (hquery.getSingleResult() == 0) {
TypedQuery<PkgData> fquery =
em.createQuery("SELECT p FROM PkgData p WHERE p.fileName = :fileName", PkgData.class);
fquery.setParameter("fileName", pkgData.getFileName());
fquery.getResultList().forEach(p -> deletePkgData(em, p));
private void persistPackage(EntityManager em, PkgData pkgData, long count, long totalPackages) {
if (Queries.countPackagesByHash(em, pkgData.getMd5sum()).getSingleResult() == 0) {
Queries.getPackageByFileName(em, pkgData.getFileName())
.getResultList()
.forEach(p -> deletePkgData(em, p));
em.persist(pkgData);
logger.info("Persisting package {}", pkgData.getFileName());
logger.info("({}/{}) Persisting package {}", count, totalPackages, pkgData.getFileName());
}
}
@@ -174,28 +180,19 @@ public class PacmanServiceEJB implements PacmanServiceLocal {
@SneakyThrows
private void deletePackage(EntityManager em, String filename) {
TypedQuery<PkgData> fquery = em.createQuery("SELECT p FROM PkgData p WHERE fileName = :fileName", PkgData.class);
fquery.setParameter("fileName", filename);
List<PkgData> savedFiles = fquery.getResultList();
List<PkgData> savedFiles = Queries.getPackageByFileName(em, filename).getResultList();
if (savedFiles.size() == 0) {
throw JWO.newThrowable(IllegalArgumentException.class, "Package with name %s not found", filename);
}
PkgData pkg = fquery.getResultList().get(0);
Files.delete(ctx.getFile(pkg));
PkgData pkg = savedFiles.get(0);
em.remove(pkg);
Files.delete(ctx.getFile(pkg));
}
static private final String deleteQuery =
"SELECT p.fileName FROM PkgData p WHERE p.buildDate < :cutoff and p.id.name in \n" + "(SELECT p2.id.name FROM PkgData p2 GROUP BY p2.id.name HAVING count(p2.id.name) > :minVersions\n)";
private void deleteOld(EntityManager em) {
TypedQuery<String> query = em.createQuery(deleteQuery, String.class);
Calendar cutoff = Calendar.getInstance();
cutoff.add(Calendar.YEAR, -2);
query.setParameter("cutoff", OffsetDateTime.now());
query.setParameter("minVersions", 2L);
List<String> list = query.getResultList();
list.forEach(this::deletePackage);
Instant cutoff = Instant.now().minus(365 * 3, ChronoUnit.DAYS);
Queries.getOldPackages2Delete(em, cutoff, 3L)
.getResultStream()
.forEach(this::deletePackage);
}
@Override
@@ -207,8 +204,101 @@ public class PacmanServiceEJB implements PacmanServiceLocal {
@Override
@TransactionAttribute(TransactionAttributeType.SUPPORTS)
public List<PkgData> searchPackage(String name, String version, String arch, int pageNumber, int pageSize, String fileName) {
public List<PkgData> searchPackage(String name,
String version,
String arch,
CompressionFormat compressionFormat,
String fileName,
int pageNumber,
int pageSize) {
EntityManager em = emf.createEntityManager();
return QueryEngine.searchPackage(em, name, version, arch, pageNumber, pageSize, null);
return Queries.searchPackage(em, name, version, arch, compressionFormat, fileName)
.setMaxResults(pageSize)
.setFirstResult(pageNumber * pageSize)
.getResultList();
}
@Override
public List<String> searchName(@Nonnull String name) {
EntityManager em = emf.createEntityManager();
return Queries.searchPackageName(em, name).getResultList();
}
@Override
public List<PkgData> searchByFileName(@Nonnull String fileName) {
EntityManager em = emf.createEntityManager();
return Queries.searchPackagesByFileName(em, fileName).getResultList();
}
@Override
public List<PkgData> searchByHash(@Nonnull String hash) {
EntityManager em = emf.createEntityManager();
return Queries.searchPackagesByHash(em, hash).getResultList();
}
@Override
public List<String> listFiles() {
EntityManager em = emf.createEntityManager();
return Queries.listFiles(em).getResultList();
}
@Override
public List<String> listHashes() {
EntityManager em = emf.createEntityManager();
return Queries.listHashes(em).getResultList();
}
@Override
@TransactionAttribute(TransactionAttributeType.SUPPORTS)
public List<PkgId> searchPkgId(
String name, String version, String arch, CompressionFormat compressionFormat) {
EntityManager em = emf.createEntityManager();
return Queries.searchPackages(em, name, version, arch, compressionFormat).getResultList();
}
@Override
@SneakyThrows
@Nullable
public Long getFileSize(String fileName) {
java.nio.file.Path res = ctx.getFile(fileName);
if (!Files.exists(res)) return null;
return Files.size(res);
}
public Set<String> missingFiles(Collection<String> fileNames) {
EntityManager em = emf.createEntityManager();
Stream<String> result = fileNames.stream();
Set<String> existing = Queries.getExistingFiles(em, fileNames)
.getResultStream().collect(CollectionUtils.toUnmodifiableTreeSet());
return result.filter(JWO.not(existing::contains))
.collect(CollectionUtils.toUnmodifiableTreeSet());
}
public NavigableMap<PkgId, PkgTuple> getPkgMap() {
EntityManager em = emf.createEntityManager();
return Queries.getPkgMap(em).getResultStream().map(tuple -> {
PkgId pkgId = tuple.get(0, PkgId.class);
String filename = tuple.get(1, String.class);
long size = tuple.get(2, Long.class);
String md5sum = tuple.get(3, String.class);;
PkgTuple pkgTuple = new PkgTuple();
pkgTuple.setFileName(filename);
pkgTuple.setSize(size);
pkgTuple.setMd5sum(md5sum);
return Tuple2.newInstance(pkgId, pkgTuple);
}).collect(
CollectionUtils.toUnmodifiableTreeMap(
Tuple2<PkgId, PkgTuple>::get_1,
Tuple2<PkgId, PkgTuple>::get_2,
PkgIdComparator.getComparator()
)
);
}
@Nullable
@Override
public PkgData getPackage(PkgId pkgId) {
EntityManager em = emf.createEntityManager();
return em.find(PkgData.class, pkgId);
}
}

View File

@@ -2,7 +2,6 @@ package net.woggioni.jpacrepo.service;
import jakarta.ejb.ConcurrencyManagement;
import jakarta.ejb.ConcurrencyManagementType;
import jakarta.ejb.Singleton;
import jakarta.ejb.TransactionAttribute;
import jakarta.ejb.TransactionAttributeType;
import jakarta.ejb.TransactionManagement;
@@ -35,7 +34,6 @@ import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.core.StreamingOutput;
import jakarta.ws.rs.core.UriInfo;
import lombok.SneakyThrows;
import lombok.val;
import net.woggioni.jpacrepo.api.model.CompressionFormat;
import net.woggioni.jpacrepo.api.model.PkgData;
import net.woggioni.jpacrepo.api.model.PkgId;
@@ -43,9 +41,9 @@ import net.woggioni.jpacrepo.api.service.PacmanServiceLocal;
import net.woggioni.jpacrepo.config.AppConfig;
import net.woggioni.jpacrepo.impl.model.CompressionFormatImpl;
import net.woggioni.jpacrepo.impl.model.PkgDataImpl;
import net.woggioni.jpacrepo.service.wire.PkgDataList;
import net.woggioni.jpacrepo.service.wire.PkgTuple;
import net.woggioni.jpacrepo.service.wire.StringList;
import net.woggioni.jpacrepo.api.wire.PkgDataList;
import net.woggioni.jpacrepo.api.wire.PkgTuple;
import net.woggioni.jpacrepo.api.wire.StringList;
import net.woggioni.jpacrepo.version.PkgIdComparator;
import net.woggioni.jpacrepo.version.VersionComparator;
import net.woggioni.jwo.CollectionUtils;
@@ -56,7 +54,6 @@ import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream;
import org.slf4j.Logger;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URI;
@@ -72,11 +69,9 @@ import java.util.Map;
import java.util.NavigableMap;
import java.util.NavigableSet;
import java.util.Optional;
import java.util.Set;
import java.util.TreeMap;
import java.util.stream.Collectors;
@Singleton
@Path("/pkg")
@ConcurrencyManagement(ConcurrencyManagementType.BEAN)
@Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
@@ -107,36 +102,7 @@ public class PacmanWebService {
synchronized(this) {
result = cachedMap;
if (result == null) {
EntityManager em = emf.createEntityManager();
TypedQuery<Object[]> query = em.createQuery(
"SELECT pkg.id.name, pkg.id.version, pkg.id.arch, pkg.id.compressionFormat, pkg.fileName, pkg.size, pkg.md5sum " +
"FROM PkgData pkg ORDER BY pkg.id.name, pkg.id.version, pkg.id.arch",
Object[].class);
cachedMap = query.getResultStream()
.map((Object[] pkg) -> {
String name = (String) pkg[0];
String version = (String) pkg[1];
String arch = (String) pkg[2];
CompressionFormat compressionFormat = (CompressionFormat) pkg[3];
String filename = (String) pkg[4];
long size = (long) pkg[5];
String md5sum = (String) pkg[6];
PkgTuple tuple = new PkgTuple();
tuple.setFilename(filename);
tuple.setSize(size);
tuple.setMd5sum(md5sum);
PkgId id = new PkgId();
id.setName(name);
id.setVersion(version);
id.setArch(arch);
id.setCompressionFormat(compressionFormat);
return Tuple2.newInstance(id, tuple);
}).collect(
CollectionUtils.toUnmodifiableTreeMap(
Tuple2<PkgId, PkgTuple>::get_1,
Tuple2<PkgId, PkgTuple>::get_2,
PkgIdComparator.getComparator())
);
cachedMap = service.getPkgMap();
ctx.getInvalidateCache().set(false);
result = cachedMap;
}
@@ -162,46 +128,26 @@ public class PacmanWebService {
@GET
@Path("searchByName/{name}")
public Response searchByName(@PathParam("name") String name) {
val em = emf.createEntityManager();
if (name == null) throw new WebApplicationException(Response.Status.BAD_REQUEST);
String query = String.format("SELECT pkgId.name FROM PkgId pkgId WHERE LOWER(pkgId.name) LIKE '%%%s%%' ORDER BY pkgId.name", name);
return Response.ok(em.createQuery(query, String.class).getResultList()).build();
return Response.ok(service.searchName(name)).build();
}
@GET
@Path("searchByHash/{md5sum}")
public Response searchByHash(@PathParam("md5sum") String md5sum) {
if (md5sum == null) throw new WebApplicationException(Response.Status.BAD_REQUEST);
return getPackageByHash(md5sum);
}
@GET
@Path("list/{name}")
public Response getPackage(@PathParam("name") String name) {
EntityManager em = emf.createEntityManager();
TypedQuery<String> query = em.createQuery("SELECT pkg.id.version FROM PkgData pkg WHERE pkg.id.name = :name ORDER BY pkg.id.version", String.class);
query.setParameter("name", name);
return Response.ok(new StringList(query.getResultList())).build();
}
@GET
@Path("list/{name}/{version}")
public Response getPackage(@PathParam("name") String name, @PathParam("version") String version) {
EntityManager em = emf.createEntityManager();
TypedQuery<String> query = em.createQuery("SELECT pkg.arch FROM PkgData pkg WHERE pkg.id.name = :name AND pkg.id.version = :version ORDER BY pkg.id.arch", String.class);
query.setParameter("name", name);
query.setParameter("version", version);
return Response.ok(new StringList(query.getResultList())).build();
}
@GET
@Path("list/{name}/{version}/{arch}")
public Response getPackage(@PathParam("name") String name, @PathParam("version") String version, @PathParam("arch") String arch) {
EntityManager em = emf.createEntityManager();
TypedQuery<PkgData> query = em.createQuery("SELECT pkg FROM PkgData pkg WHERE " + "pkg.id.name = :name AND " + "pkg.id.version = :version AND " + "pkg.id.arch = :arch " + "ORDER BY pkg.arch", PkgData.class);
query.setParameter("name", name);
query.setParameter("version", version);
query.setParameter("arch", arch);
return Response.ok(query.getSingleResult()).build();
@Path("id/search")
public Response searchPackages(
@QueryParam("name") String name,
@QueryParam("version") String version,
@QueryParam("arch") String arch,
@QueryParam("compressionFormat") CompressionFormat compressionFormat
) {
return Response.ok(service.searchPkgId(name, version, arch, compressionFormat)).build();
}
@GET
@@ -213,7 +159,7 @@ public class PacmanWebService {
cc.setMustRevalidate(true);
cc.setNoCache(true);
NavigableMap<PkgId, PkgTuple> cachedMap = getCachedMap();
NavigableMap<PkgId, PkgTuple> cachedMap = service.getPkgMap();
EntityTag etag = new EntityTag(Integer.toString(cachedMap.hashCode()), false);
Response.ResponseBuilder builder = request.evaluatePreconditions(etag);
if (builder == null) {
@@ -227,7 +173,7 @@ public class PacmanWebService {
Collectors.mapping(
Map.Entry::getValue,
CollectionUtils.toUnmodifiableTreeSet(
Comparator.comparing(PkgTuple::getFilename)
Comparator.comparing(PkgTuple::getFileName)
)
)
)
@@ -244,31 +190,27 @@ public class PacmanWebService {
@GET
@Path("hashes")
public Response getHashes() {
EntityManager em = emf.createEntityManager();
TypedQuery<String> query = em.createQuery("SELECT p.md5sum FROM PkgData p", String.class);
return Response.ok(new StringList(query.getResultList())).build();
return Response.ok(new StringList(service.listHashes())).build();
}
@GET
@Path("files")
public Response getFiles() {
EntityManager em = emf.createEntityManager();
TypedQuery<String> query = em.createQuery("SELECT p.fileName FROM PkgData p", String.class);
return Response.ok(new StringList(query.getResultList())).build();
return Response.ok(new StringList(service.listFiles())).build();
}
private Response getPackageByHash(String md5sum) {
EntityManager em = emf.createEntityManager();
TypedQuery<PkgData> hquery = em.createNamedQuery("searchByHash", PkgData.class);
if (md5sum != null) hquery.setParameter("md5sum", md5sum);
return manageQueryResult(hquery.getResultList(), true);
return manageQueryResult(service.searchByHash(md5sum), true);
}
private Response getPackageByFileName(String file) {
EntityManager em = emf.createEntityManager();
TypedQuery<PkgData> fnquery = em.createNamedQuery("searchByFileName", PkgData.class);
fnquery.setParameter("fileName", file);
return manageQueryResult(fnquery.getResultList(), true);
@GET
@Path("file/{fileName}")
private Response getPackageByFileName(String fileName) {
try {
return Response.ok(service.searchByFileName(fileName)).build();
} catch (NoResultException nre) {
return Response.status(Response.Status.NOT_FOUND).build();
}
}
@GET
@@ -282,9 +224,9 @@ public class PacmanWebService {
EntityTag etag = new EntityTag(Integer.toString(getCachedMap().hashCode()));
Response.ResponseBuilder builder = request.evaluatePreconditions(etag);
if (builder == null) {
java.nio.file.Path res = ctx.getFile(fileName);
if (!Files.exists(res)) throw new NotFoundException(String.format("File '%s' was not found", fileName));
builder = Response.ok(Files.size(res));
Long size = service.getFileSize(fileName);
if (size == null) throw new NotFoundException(String.format("File '%s' was not found", fileName));
builder = Response.ok(size);
builder.tag(etag);
}
builder.cacheControl(cc);
@@ -296,37 +238,31 @@ public class PacmanWebService {
@Path("download/{filename}")
@Produces(MediaType.APPLICATION_OCTET_STREAM)
public Response downloadPackage(@PathParam("filename") String fileName) {
EntityManager em = emf.createEntityManager();
TypedQuery<PkgData> fnquery = em.createNamedQuery("searchByFileName", PkgData.class);
fnquery.setParameter("fileName", fileName);
try {
PkgData pkg = fnquery.getSingleResult();
List<PkgData> pkgs = service.searchByFileName(fileName);
if(pkgs.isEmpty()) {
return Response.status(Response.Status.NOT_FOUND).build();
} else if(pkgs.size() == 1) {
PkgData pkg = pkgs.get(0);
StreamingOutput stream = (OutputStream output) -> {
try(InputStream is = Files.newInputStream(ctx.getFile(pkg))) {
try (InputStream is = Files.newInputStream(ctx.getFile(pkg))) {
JWO.copy(is, output, 0x10000);
}
};
return Response.ok(stream).header("Content-Length", Files.size(ctx.getFile(pkg))).build();
} catch(NoResultException nre) {
throw new NotFoundException();
} else {
throw new RuntimeException("This should never happen");
}
}
@POST
@Path("/doYouWantAny")
@Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
public Response doYouWantAny(List<String> filenames) {
EntityManager em = emf.createEntityManager();
Set<String> result = filenames.stream().collect(CollectionUtils.toTreeSet());
if (!result.isEmpty()) {
TypedQuery<String> query = em.createQuery("SELECT pkg.fileName from PkgData pkg WHERE pkg.fileName in :filenames", String.class);
query.setParameter("filenames", filenames);
Set<String> toBeRemoved = query.getResultStream().collect(CollectionUtils.toTreeSet());
result.removeAll(toBeRemoved);
return Response.ok(new StringList(result)).build();
public Response doYouWantAny(List<String> fileNames) {
if (fileNames.isEmpty()) {
return Response.ok(fileNames).build();
}
else {
return Response.ok(result.toArray()).build();
return Response.ok(new StringList(service.missingFiles(fileNames))).build();
}
}
@@ -342,9 +278,7 @@ public class PacmanWebService {
EntityManager em = emf.createEntityManager();
if (filename == null) throw new BadRequestException();
java.nio.file.Path file = Files.createTempFile(ctx.getRepoFolder(), filename, null);
TypedQuery<PkgData> fquery = em.createNamedQuery("searchByFileName", PkgData.class);
fquery.setParameter("fileName", filename);
List<PkgData> savedFiles = fquery.getResultList();
List<PkgData> savedFiles = service.searchByFileName(filename);
Response result;
if (savedFiles.size() > 0) result = Response.notModified().build();
else {
@@ -374,14 +308,23 @@ public class PacmanWebService {
@GET
@Path("/search")
public List<PkgData> searchPackage(
public PkgDataList searchPackage(
@QueryParam("name") String name,
@QueryParam("version") String version,
@QueryParam("arch") String arch,
@QueryParam("compressionFormat") CompressionFormat compressionFormat,
@QueryParam("fileName") String fileName,
@QueryParam("page") int pageNumber,
@QueryParam("pageSize") int pageSize,
@QueryParam("fileName") String fileName) {
return service.searchPackage(name, version, arch, pageNumber, pageSize, fileName);
@QueryParam("pageSize") int pageSize) {
return new PkgDataList(service.searchPackage(
name,
version,
arch,
compressionFormat,
fileName,
pageNumber,
Optional.of(pageSize).filter(it -> it > 0).orElse(10)
));
}
@OPTIONS

View File

@@ -0,0 +1,281 @@
package net.woggioni.jpacrepo.service.jpa;
import jakarta.persistence.EntityManager;
import jakarta.persistence.Tuple;
import jakarta.persistence.TypedQuery;
import jakarta.persistence.criteria.CriteriaBuilder;
import jakarta.persistence.criteria.CriteriaQuery;
import jakarta.persistence.criteria.Path;
import jakarta.persistence.criteria.Predicate;
import jakarta.persistence.criteria.Root;
import jakarta.persistence.criteria.Subquery;
import jakarta.persistence.metamodel.EntityType;
import jakarta.persistence.metamodel.Metamodel;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import net.woggioni.jpacrepo.api.model.CompressionFormat;
import net.woggioni.jpacrepo.api.model.PkgData;
import net.woggioni.jpacrepo.api.model.PkgData_;
import net.woggioni.jpacrepo.api.model.PkgId;
import net.woggioni.jpacrepo.api.model.PkgId_;
import net.woggioni.jwo.JWO;
import java.time.Instant;
import java.util.Collection;
import java.util.Optional;
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class Queries {
private interface PredicateSupplier<T> {
Predicate get(CriteriaBuilder cb, Root<T> root);
}
public static TypedQuery<String> listAllPackageFiles(EntityManager em) {
CriteriaBuilder cb = em.getCriteriaBuilder();
Metamodel metamodel = em.getMetamodel();
CriteriaQuery<String> criteriaQuery = cb.createQuery(String.class);
Root<PkgData> root = criteriaQuery.from(metamodel.entity(PkgData.class));
criteriaQuery.select(root.get(PkgData_.fileName));
return em.createQuery(criteriaQuery);
}
public static TypedQuery<PkgData> getPackageByFileName(EntityManager em, String fileName) {
CriteriaBuilder cb = em.getCriteriaBuilder();
Metamodel metamodel = em.getMetamodel();
EntityType<PkgData> entity = metamodel.entity(PkgData.class);
CriteriaQuery<PkgData> criteriaQuery = cb.createQuery(PkgData.class);
Root<PkgData> root = criteriaQuery.from(entity);
Predicate predicate = cb.equal(root.get(PkgData_.fileName), fileName);
criteriaQuery.select(root).where(predicate);
return em.createQuery(criteriaQuery);
}
public static TypedQuery<Instant> getUpdateTimestampByFileName(EntityManager em, String fileName) {
CriteriaBuilder cb = em.getCriteriaBuilder();
Metamodel metamodel = em.getMetamodel();
EntityType<PkgData> entity = metamodel.entity(PkgData.class);
CriteriaQuery<Instant> criteriaQuery = cb.createQuery(Instant.class);
Root<PkgData> root = criteriaQuery.from(entity);
Predicate predicate = cb.equal(root.get(PkgData_.fileName), fileName);
criteriaQuery.select(root.get(PkgData_.updTimestamp)).where(predicate);
return em.createQuery(criteriaQuery);
}
public static TypedQuery<String> getOldPackages2Delete(
EntityManager em,
Instant cutoff,
long minNumberOfDifferentVersions) {
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<String> criteriaQuery = cb.createQuery(String.class);
Metamodel metamodel = em.getMetamodel();
EntityType<PkgData> entity = metamodel.entity(PkgData.class);
Root<PkgData> pkgDataRoot = criteriaQuery.from(entity);
Subquery<String> subQuery = criteriaQuery.subquery(String.class);
Root<PkgData> pkgDataRootSub = subQuery.from(entity);
Path<PkgId> pkgIdPathSub = pkgDataRootSub.get(PkgData_.id);
Predicate havingPredicate = cb.greaterThan(cb.count(
pkgIdPathSub.get(PkgId_.version)), minNumberOfDifferentVersions);
subQuery.select(pkgIdPathSub.get(PkgId_.name))
.groupBy(
pkgIdPathSub.get(PkgId_.name),
pkgIdPathSub.get(PkgId_.arch)
).having(havingPredicate);
Predicate predicate = cb.and(
cb.lessThan(pkgDataRoot.get(PkgData_.buildDate), cutoff),
pkgDataRoot.get(PkgData_.id).get(PkgId_.name).in(subQuery.getSelection())
);
criteriaQuery.select(pkgDataRoot.get(PkgData_.fileName))
.where(predicate)
.orderBy(cb.asc(pkgDataRoot.get(PkgData_.fileName)));
return em.createQuery(criteriaQuery);
}
public static TypedQuery<Long> countPackagesByHash(EntityManager em, String hash) {
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Long> criteriaQuery = cb.createQuery(Long.class);
Metamodel metamodel = em.getMetamodel();
EntityType<PkgData> entity = metamodel.entity(PkgData.class);
Root<PkgData> pkgDataRoot = criteriaQuery.from(entity);
Predicate predicate = cb.equal(pkgDataRoot.get(PkgData_.md5sum), hash);
criteriaQuery.select(cb.count(pkgDataRoot)).where(predicate);
return em.createQuery(criteriaQuery);
}
private static <T> TypedQuery<PkgData> searchPackagesByPredicate(EntityManager em,
PredicateSupplier<PkgData> predicateSupplier) {
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<PkgData> criteriaQuery = cb.createQuery(PkgData.class);
Metamodel metamodel = em.getMetamodel();
EntityType<PkgData> entity = metamodel.entity(PkgData.class);
Root<PkgData> pkgDataRoot = criteriaQuery.from(entity);
criteriaQuery.select(pkgDataRoot).where(predicateSupplier.get(cb, pkgDataRoot));
return em.createQuery(criteriaQuery);
}
public static TypedQuery<PkgData> searchPackagesByHash(EntityManager em, String hash) {
return searchPackagesByPredicate(em, (cb, root) -> cb.equal(root.get(PkgData_.md5sum), hash));
}
public static TypedQuery<PkgData> searchPackagesByFileName(EntityManager em, String fileName) {
return searchPackagesByPredicate(em, (cb, root) -> cb.equal(root.get(PkgData_.fileName), fileName));
}
public static TypedQuery<Long> getSize(EntityManager em, String fileName) {
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Long> criteriaQuery = cb.createQuery(Long.class);
Metamodel metamodel = em.getMetamodel();
EntityType<PkgData> entity = metamodel.entity(PkgData.class);
Root<PkgData> pkgDataRoot = criteriaQuery.from(entity);
Predicate predicate = cb.equal(pkgDataRoot.get(PkgData_.fileName), fileName);
criteriaQuery.select(pkgDataRoot.get(PkgData_.size)).where(predicate);
return em.createQuery(criteriaQuery);
}
public static TypedQuery<String> searchPackageName(EntityManager em, String needle) {
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<String> criteriaQuery = cb.createQuery(String.class);
Metamodel metamodel = em.getMetamodel();
EntityType<PkgData> entity = metamodel.entity(PkgData.class);
Root<PkgData> root = criteriaQuery.from(entity);
Path<PkgId> pkgIdPath = root.get(PkgData_.id);
Predicate predicate = cb.like(
cb.lower(pkgIdPath.get(PkgId_.name)),
"%%" + needle + "%%"
);
criteriaQuery.select(pkgIdPath.get(PkgId_.name))
.where(predicate)
.orderBy(cb.asc(pkgIdPath.get(PkgId_.name)));
return em.createQuery(criteriaQuery);
}
public static TypedQuery<String> listFiles(EntityManager em) {
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<String> criteriaQuery = cb.createQuery(String.class);
Metamodel metamodel = em.getMetamodel();
EntityType<PkgData> entity = metamodel.entity(PkgData.class);
Root<PkgData> root = criteriaQuery.from(entity);
criteriaQuery.select(root.get(PkgData_.fileName))
.orderBy(cb.asc(root.get(PkgData_.fileName)));
return em.createQuery(criteriaQuery);
}
public static TypedQuery<String> listHashes(EntityManager em) {
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<String> criteriaQuery = cb.createQuery(String.class);
Metamodel metamodel = em.getMetamodel();
EntityType<PkgData> entity = metamodel.entity(PkgData.class);
Root<PkgData> root = criteriaQuery.from(entity);
criteriaQuery.select(root.get(PkgData_.md5sum))
.orderBy(cb.asc(root.get(PkgData_.md5sum)));
return em.createQuery(criteriaQuery);
}
public static TypedQuery<PkgId> searchPackages(EntityManager em,
String name,
String version,
String arch,
CompressionFormat compressionFormat) {
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<PkgId> criteriaQuery = cb.createQuery(PkgId.class);
Metamodel metamodel = em.getMetamodel();
EntityType<PkgData> entity = metamodel.entity(PkgData.class);
Root<PkgData> root = criteriaQuery.from(entity);
Path<PkgId> pkgIdRoot = root.get(PkgData_.id);
Predicate[] predicates = JWO.streamCat(
Optional.ofNullable(name)
.map(it -> cb.equal(pkgIdRoot.get(PkgId_.name), it)).stream(),
Optional.ofNullable(version)
.map(it -> cb.equal(pkgIdRoot.get(PkgId_.version), it)).stream(),
Optional.ofNullable(arch)
.map(it -> cb.equal(pkgIdRoot.get(PkgId_.name), it)).stream(),
Optional.ofNullable(compressionFormat)
.map(it -> cb.equal(pkgIdRoot.get(PkgId_.compressionFormat), it)).stream()
).toArray(Predicate[]::new);
criteriaQuery.select(pkgIdRoot)
.where(cb.and(predicates))
.orderBy(
cb.asc(pkgIdRoot.get(PkgId_.name)),
cb.asc(pkgIdRoot.get(PkgId_.version)),
cb.asc(pkgIdRoot.get(PkgId_.arch)),
cb.asc(pkgIdRoot.get(PkgId_.compressionFormat))
);
return em.createQuery(criteriaQuery);
}
public static TypedQuery<String> getExistingFiles(EntityManager em, Collection<String> fileNames) {
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<String> criteriaQuery = cb.createQuery(String.class);
Metamodel metamodel = em.getMetamodel();
EntityType<PkgData> entity = metamodel.entity(PkgData.class);
Root<PkgData> root = criteriaQuery.from(entity);
Predicate predicate = root.get(PkgData_.fileName).in(fileNames);
criteriaQuery.select(root.get(PkgData_.fileName)).where(predicate);
return em.createQuery(criteriaQuery);
}
public static TypedQuery<Tuple> getPkgMap(EntityManager em) {
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Tuple> criteriaQuery = cb.createTupleQuery();
Metamodel metamodel = em.getMetamodel();
EntityType<PkgData> entity = metamodel.entity(PkgData.class);
Root<PkgData> root = criteriaQuery.from(entity);
Path<PkgId> idPath = root.get(PkgData_.id);
criteriaQuery.multiselect(
idPath,
root.get(PkgData_.fileName),
root.get(PkgData_.size),
root.get(PkgData_.md5sum)
).orderBy(
cb.asc(idPath.get(PkgId_.arch)),
cb.asc(idPath.get(PkgId_.name)),
cb.asc(idPath.get(PkgId_.version)),
cb.asc(idPath.get(PkgId_.compressionFormat))
);
return em.createQuery(criteriaQuery);
}
public static TypedQuery<PkgData> searchPackage(
EntityManager em, String name,
String version,
String arch,
CompressionFormat compressionFormat,
String fileName) {
CriteriaQuery<PkgData> criteriaQuery;
CriteriaBuilder builder = em.getCriteriaBuilder();
criteriaQuery = builder.createQuery(PkgData.class);
Root<PkgData> entity = criteriaQuery.from(PkgData.class);
Path<PkgId> pkgIdPath = entity.get(PkgData_.id);
Predicate predicate = builder.and(JWO.streamCat(
JWO.optional2Stream(
Optional.ofNullable(name)
.filter(JWO.not(String::isEmpty))
.map(it -> builder.equal(pkgIdPath.get(PkgId_.name), it))),
JWO.optional2Stream(
Optional.ofNullable(version)
.filter(JWO.not(String::isEmpty))
.map(it -> builder.equal(pkgIdPath.get(PkgId_.version), it))),
JWO.optional2Stream(
Optional.ofNullable(arch)
.filter(JWO.not(String::isEmpty))
.map(it -> builder.equal(pkgIdPath.get(PkgId_.arch), it))),
JWO.optional2Stream(
Optional.ofNullable(compressionFormat)
.map(it -> builder.equal(pkgIdPath.get(PkgId_.compressionFormat), it))),
JWO.optional2Stream(
Optional.ofNullable(fileName)
.filter(JWO.not(String::isEmpty))
.map(it -> builder.equal(entity.get(PkgData_.fileName), it)))
).toArray(Predicate[]::new));
criteriaQuery.select(entity)
.where(predicate)
.orderBy(
builder.asc(pkgIdPath.get(PkgId_.name)),
builder.asc(pkgIdPath.get(PkgId_.version)),
builder.asc(pkgIdPath.get(PkgId_.arch)),
builder.asc(pkgIdPath.get(PkgId_.compressionFormat)),
builder.asc(entity.get(PkgData_.fileName))
);
return em.createQuery(criteriaQuery);
}
}

View File

@@ -0,0 +1,35 @@
package net.woggioni.jpacrepo.service.jpa;
import jakarta.persistence.EntityManager;
import jakarta.persistence.TypedQuery;
import jakarta.persistence.criteria.CriteriaBuilder;
import jakarta.persistence.criteria.CriteriaQuery;
import jakarta.persistence.criteria.Root;
import jakarta.persistence.criteria.Selection;
import jakarta.persistence.metamodel.Metamodel;
public class QueryBuilder<T> {
private final EntityManager em;
private final CriteriaBuilder cb;
private final CriteriaQuery<T> criteriaQuery;
private final Metamodel metamodel;
public QueryBuilder(EntityManager em, Class<T> cls) {
this.em = em;
this.cb = em.getCriteriaBuilder();
this.criteriaQuery = cb.createQuery(cls);
this.metamodel = em.getMetamodel();
}
public QueryBuilder<T> select(Selection<? extends T> a) {
criteriaQuery.select(a);
return this;
}
public <U> Root<U> from(Class<U> cls) {
return criteriaQuery.from(metamodel.entity(cls));
}
public TypedQuery<T> build() {
return em.createQuery(criteriaQuery);
}
}

View File

@@ -0,0 +1,5 @@
<beans xmlns="https://jakarta.ee/xml/ns/jakartaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/beans_4_0.xsd"
version="4.0" bean-discovery-mode="annotated">
</beans>

View File

@@ -11,14 +11,14 @@
<properties>
<property name="org.jboss.logging.provider" value="log4j2"/>
<property name="javax.persistence.schema-generation.create-source" value="script-then-metadata"/>
<property name="javax.persistence.schema-generation.create-script-source"
<property name="jakarta.persistence.schema-generation.create-source" value="script-then-metadata"/>
<property name="jakarta.persistence.schema-generation.create-script-source"
value="META-INF/sql/CreateSchema.sql"/>
<property name="javax.persistence.schema-generation.drop-source" value="metadata-then-script"/>
<property name="javax.persistence.schema-generation.drop-script-source"
<property name="jakarta.persistence.schema-generation.drop-source" value="metadata-then-script"/>
<property name="jakarta.persistence.schema-generation.drop-script-source"
value="META-INF/sql/DropSchema.sql"/>
<property name="hibernate.default_schema" value="jpacrepo"/>
<property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQL82Dialect"/>
<property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQLDialect"/>
</properties>
</persistence-unit>
</persistence>

View File

@@ -12,7 +12,7 @@
<error-page>
<error-code>404</error-code>
<location>404.xhtml</location>
<location>/404.xhtml</location>
</error-page>
</web-app>

View File

@@ -116,6 +116,7 @@ public class ClientTest {
}
}
@Test
public void invokeStatelessBean() throws Exception {
Properties prop = new Properties();
InputStream in = getClass().getClassLoader().getResourceAsStream("jboss-ejb-client.properties");
@@ -123,13 +124,13 @@ public class ClientTest {
prop.put(Context.URL_PKG_PREFIXES, "org.jboss.ejb.client.naming");
prop.put(Context.INITIAL_CONTEXT_FACTORY, "org.jboss.naming.remote.client.InitialContextFactory");
prop.put(Context.PROVIDER_URL, "http-remoting://localhost:8080");
// prop.put(Context.PROVIDER_URL, "http-remoting://nuc:8080");
prop.put(Context.PROVIDER_URL, "http-remoting://localhost:7080");
// prop.put(Context.PROVIDER_URL, "http-remoting://localhost:8080");
// prop.put(Context.PROVIDER_URL, "remote://odroid-u3:4447");
// prop.put(Context.SECURITY_PRINCIPAL, "walter");
// prop.put(Context.SECURITY_CREDENTIALS, "27ff5990757d1d");
prop.put(Context.SECURITY_PRINCIPAL, "luser");
prop.put(Context.SECURITY_CREDENTIALS, "123456");
prop.put(Context.SECURITY_PRINCIPAL, "walter");
prop.put(Context.SECURITY_CREDENTIALS, "27ff5990757d1d");
// prop.put(Context.SECURITY_PRINCIPAL, "luser");
// prop.put(Context.SECURITY_CREDENTIALS, "123456");
prop.put("jboss.naming.client.ejb.context", true);
Context context = new InitialContext(prop);
@@ -137,11 +138,21 @@ public class ClientTest {
traverseJndiNode("/", context);
// final PacmanService stateService = (PacmanService) ctx.lookup("/jpacrepo-1.0/remote/PacmanServiceEJB!service.PacmanService");
final PacmanServiceRemote service = (PacmanServiceRemote) ctx.lookup(
"/jpacrepo-2.0-SNAPSHOT/PacmanServiceEJB!net.woggioni.jpacrepo.service.PacmanServiceRemote"
"/jpacrepo-2023.07/PacmanServiceEJB!net.woggioni.jpacrepo.api.service.PacmanServiceRemote"
);
// List<PkgData> pkgs = service.searchPackage("google-earth", null, null, 1, 10);
// System.out.println(new XStream().toXML(pkgs));
service.syncDB();
// service.searchPkgId("jre8-openjdk", null, null, null)
// .stream()
// .map(service::getPackage)
// .filter(Objects::nonNull)
// .map(PkgData::getFileName)
// .forEach(System.out::println);
// final TestEJB service = (TestEJB) ctx.lookup(
// "/jpacrepo-2023.07TestEJBImpl!net.woggioni.jpacrepo.api.service.TestEJB"
// );
// System.out.println(service.hello());
}
}

View File

@@ -0,0 +1,34 @@
import jakarta.ejb.embeddable.EJBContainer;
import org.junit.jupiter.api.BeforeEach;
import javax.naming.Context;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.Locale;
import java.util.Properties;
public class EJBTest {
private EJBContainer ejbContainer = null;
private Context context = null;
@BeforeEach
public void init() {
Arrays.stream(System.getProperty("java.class.path").split(System.getProperty("path.separator")))
.filter(it -> it.toLowerCase(Locale.ROOT).endsWith(".war"))
.forEach(System.out::println);
Properties properties = new Properties();
File[] files = Arrays.stream(System.getProperty("jpacrepo.jar.path").split(System.getProperty("path.separator")))
.map(Path::of)
.filter(Files::exists)
.map(Path::toFile)
.toArray(File[]::new);
properties.put(EJBContainer.MODULES, files);
ejbContainer = EJBContainer.createEJBContainer(properties);
context = ejbContainer.getContext();
}
}