improved data architecture

This commit is contained in:
2024-02-09 22:43:31 +08:00
parent f77a5c3e0d
commit e3d99fa178
34 changed files with 1188 additions and 267 deletions

View File

@@ -18,7 +18,13 @@ allprojects {
}
tasks.withType(JavaCompile) {
options.release = 17
options.release = 21
}
java {
toolchain {
languageVersion = JavaLanguageVersion.of(21)
}
}
tasks.withType(Test) {
@@ -76,11 +82,12 @@ dependencies {
implementation catalog.commons.compress
implementation catalog.jna
implementation catalog.liquibase.cdi.jakarta
testImplementation catalog.jackson.module.jakarta.xmlbind.annotations
testImplementation catalog.jboss.ejb.client
testImplementation catalog.weld.se.core
testImplementation catalog.h2
// testImplementation catalog.h2
testImplementation catalog.hibernate.core
testImplementation catalog.resteasy.client
testImplementation catalog.resteasy.jackson2.provider
@@ -113,13 +120,14 @@ Provider<Exec> nimCompileTaskProvider = tasks.register("compileNim", Exec) {
workingDir(nimDir)
}
Provider<War> warTaskProvider = tasks.named('war', War) {
Provider<War> warTaskProvider = tasks.named('war', War) { War it ->
from staticDir
from nimCompileTaskProvider
archiveVersion = ''
}
tasks.named('deploy2Wildfly', Deploy2WildflyTask) { d2w ->
d2w.rpcPort = 1234
d2w.rpcPort = 9990
d2w.rpcUsername = 'woggioni'
// d2w.rpcUsername = 'admin'
d2w.rpcPassword = '123456'

View File

@@ -1,3 +1,3 @@
jpacrepo.version=2023.10.04
jpacrepo.version=2024.02.09
lys.version=2023.10.01
lys.version=2024.02.09

Binary file not shown.

View File

@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME

3
gradlew vendored
View File

@@ -83,7 +83,8 @@ done
# This is normally unused
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum

View File

@@ -7,9 +7,13 @@ dependencies {
compileOnly catalog.jakarta.persistence.api
compileOnly catalog.jakarta.inject.api
compileOnly catalog.jakarta.ejb.api
compileOnly catalog.jakarta.enterprise.cdi.api
compileOnly catalog.jakarta.json.bind.api
compileOnly catalog.jakarta.json.api
compileOnly catalog.jakarta.annotation.api
compileOnly catalog.slf4j.api
// compileOnly catalog.hibernate.core
implementation catalog.liquibase.core
annotationProcessor catalog.hibernate.jpamodelgen
}

View File

@@ -5,6 +5,8 @@ module net.woggioni.jpacrepo.api {
requires jakarta.persistence;
requires jakarta.annotation;
requires jakarta.json.bind;
requires jakarta.cdi;
requires jakarta.json;
exports net.woggioni.jpacrepo.api.model;
exports net.woggioni.jpacrepo.api.service;

View File

@@ -0,0 +1,16 @@
package net.woggioni.jpacrepo.api.jsonb;
import jakarta.json.bind.serializer.JsonbSerializer;
import jakarta.json.bind.serializer.SerializationContext;
import jakarta.json.stream.JsonGenerator;
import net.woggioni.jpacrepo.api.model.NamedEntity;
public class NamedEntitySerializer implements JsonbSerializer<NamedEntity> {
@Override
public void serialize(
NamedEntity namedEntity,
JsonGenerator jsonGenerator,
SerializationContext serializationContext) {
serializationContext.serialize(namedEntity.getName(), jsonGenerator);
}
}

View File

@@ -0,0 +1,22 @@
package net.woggioni.jpacrepo.api.jsonb;
import jakarta.json.bind.serializer.JsonbSerializer;
import jakarta.json.bind.serializer.SerializationContext;
import jakarta.json.stream.JsonGenerator;
import net.woggioni.jpacrepo.api.model.NamedEntity;
import java.util.Set;
public class SetSerializer implements JsonbSerializer<Set<NamedEntity>> {
@Override
public void serialize(
Set<NamedEntity> namedEntities,
JsonGenerator jsonGenerator,
SerializationContext serializationContext) {
jsonGenerator.writeStartArray();
for(NamedEntity namedEntity : namedEntities) {
serializationContext.serialize(namedEntity.getName(), jsonGenerator);
}
jsonGenerator.writeEnd();
}
}

View File

@@ -0,0 +1,40 @@
package net.woggioni.jpacrepo.api.model;
import jakarta.json.bind.annotation.JsonbTypeSerializer;
import jakarta.persistence.Access;
import jakarta.persistence.AccessType;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;
import jakarta.persistence.Inheritance;
import jakarta.persistence.InheritanceType;
import jakarta.xml.bind.annotation.XmlAccessType;
import jakarta.xml.bind.annotation.XmlAccessorType;
import jakarta.xml.bind.annotation.XmlRootElement;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import net.woggioni.jpacrepo.api.jsonb.NamedEntitySerializer;
import java.util.Comparator;
import java.util.Objects;
import java.util.jar.Attributes;
@Entity
@Access(AccessType.PROPERTY)
@XmlRootElement
@XmlAccessorType(XmlAccessType.PROPERTY)
@JsonbTypeSerializer(NamedEntitySerializer.class)
public class Dependency extends NamedEntity implements Comparable<Dependency> {
public static Dependency of(String name) {
var result = new Dependency();
result.setName(name);
return result;
}
@Override
public int compareTo(Dependency o) {
return super.compareTo(o);
}
}

View File

@@ -0,0 +1,30 @@
package net.woggioni.jpacrepo.api.model;
import jakarta.json.bind.annotation.JsonbTypeSerializer;
import jakarta.persistence.Access;
import jakarta.persistence.AccessType;
import jakarta.persistence.Entity;
import jakarta.persistence.Inheritance;
import jakarta.persistence.InheritanceType;
import jakarta.xml.bind.annotation.XmlAccessType;
import jakarta.xml.bind.annotation.XmlAccessorType;
import jakarta.xml.bind.annotation.XmlRootElement;
import net.woggioni.jpacrepo.api.jsonb.NamedEntitySerializer;
@Entity
@Access(AccessType.PROPERTY)
@XmlRootElement
@XmlAccessorType(XmlAccessType.PROPERTY)
@JsonbTypeSerializer(NamedEntitySerializer.class)
public class License extends NamedEntity implements Comparable<License> {
public static License of(String name) {
var result = new License();
result.setName(name);
return result;
}
@Override
public int compareTo(License o) {
return super.compareTo(o);
}
}

View File

@@ -0,0 +1,56 @@
package net.woggioni.jpacrepo.api.model;
import jakarta.json.bind.annotation.JsonbTypeSerializer;
import jakarta.persistence.Access;
import jakarta.persistence.AccessType;
import jakarta.persistence.Column;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;
import jakarta.persistence.MappedSuperclass;
import jakarta.xml.bind.annotation.XmlTransient;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import net.woggioni.jpacrepo.api.jsonb.NamedEntitySerializer;
import java.util.Comparator;
import java.util.Objects;
@Getter
@Setter
@Access(AccessType.PROPERTY)
@NoArgsConstructor
@MappedSuperclass
@JsonbTypeSerializer(NamedEntitySerializer.class)
public abstract class NamedEntity {
@Getter(onMethod_ = {
@Column(unique = true, length = 1024),
})
private String name;
@Getter(onMethod_ = {
@Id,
@GeneratedValue,
@XmlTransient
})
private long id;
@Override
public int hashCode() {
return name.hashCode();
}
@Override
public boolean equals(Object obj) {
if(obj.getClass() == getClass()) {
NamedEntity other = (NamedEntity) obj;
return Objects.equals(getName(), other.getName());
} else {
return false;
}
}
public int compareTo(NamedEntity o) {
return Comparator.<String>naturalOrder().compare(getName(), o.getName());
}
}

View File

@@ -0,0 +1,28 @@
package net.woggioni.jpacrepo.api.model;
import jakarta.json.bind.annotation.JsonbTypeSerializer;
import jakarta.persistence.Access;
import jakarta.persistence.AccessType;
import jakarta.persistence.Entity;
import jakarta.xml.bind.annotation.XmlAccessType;
import jakarta.xml.bind.annotation.XmlAccessorType;
import jakarta.xml.bind.annotation.XmlRootElement;
import net.woggioni.jpacrepo.api.jsonb.NamedEntitySerializer;
@Entity
@Access(AccessType.PROPERTY)
@XmlRootElement
@XmlAccessorType(XmlAccessType.PROPERTY)
@JsonbTypeSerializer(NamedEntitySerializer.class)
public class Packager extends NamedEntity implements Comparable<Packager> {
public static Packager of(String name) {
var result = new Packager();
result.setName(name);
return result;
}
@Override
public int compareTo(Packager o) {
return super.compareTo(o);
}
}

View File

@@ -0,0 +1,31 @@
package net.woggioni.jpacrepo.api.model;
import jakarta.json.bind.annotation.JsonbTypeSerializer;
import jakarta.persistence.Access;
import jakarta.persistence.AccessType;
import jakarta.persistence.Entity;
import jakarta.persistence.Inheritance;
import jakarta.persistence.InheritanceType;
import jakarta.xml.bind.annotation.XmlAccessType;
import jakarta.xml.bind.annotation.XmlAccessorType;
import jakarta.xml.bind.annotation.XmlRootElement;
import net.woggioni.jpacrepo.api.jsonb.NamedEntitySerializer;
@Entity
@Access(AccessType.PROPERTY)
@XmlRootElement
@XmlAccessorType(XmlAccessType.PROPERTY)
@JsonbTypeSerializer(NamedEntitySerializer.class)
public class PkgBase extends NamedEntity implements Comparable<PkgBase> {
public static PkgBase of(String name) {
var result = new PkgBase();
result.setName(name);
return result;
}
@Override
public int compareTo(PkgBase o) {
return super.compareTo(o);
}
}

View File

@@ -1,17 +1,18 @@
package net.woggioni.jpacrepo.api.model;
import jakarta.json.bind.annotation.JsonbTransient;
import jakarta.json.bind.annotation.JsonbVisibility;
import jakarta.json.bind.config.PropertyVisibilityStrategy;
import jakarta.json.bind.annotation.JsonbTypeSerializer;
import jakarta.persistence.Access;
import jakarta.persistence.AccessType;
import jakarta.persistence.ElementCollection;
import jakarta.persistence.EmbeddedId;
import jakarta.persistence.Column;
import jakarta.persistence.Embedded;
import jakarta.persistence.Entity;
import jakarta.persistence.FetchType;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;
import jakarta.persistence.Index;
import jakarta.persistence.NamedQueries;
import jakarta.persistence.NamedQuery;
import jakarta.persistence.JoinTable;
import jakarta.persistence.ManyToMany;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.PrePersist;
import jakarta.persistence.PreUpdate;
import jakarta.persistence.Table;
@@ -19,73 +20,144 @@ 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 lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import net.woggioni.jpacrepo.api.jsonb.SetSerializer;
import java.io.Serializable;
import java.time.Instant;
import java.util.Objects;
import java.util.Set;
@Data
@Setter
@Getter
@NoArgsConstructor
@Entity
@Access(AccessType.FIELD)
@NamedQueries(value = {
@NamedQuery(name = "searchByFileName", query = "SELECT p FROM PkgData p WHERE p.fileName = :fileName"),
@NamedQuery(name = "searchByName", query = "SELECT p FROM PkgData p WHERE p.id.name = :name"),
@NamedQuery(name = "searchById", query = "SELECT p FROM PkgData p WHERE p.id = :id"),
@NamedQuery(name = "searchByHash", query = "SELECT p FROM PkgData p WHERE p.md5sum = :md5sum")
})
@Access(AccessType.PROPERTY)
@Table(indexes = {
@Index(columnList = "md5sum", unique = true),
@Index(columnList = "fileName", unique = true)
@Index(columnList = "fileName", unique = true),
@Index(columnList = "name, version, arch, compressionformat", unique = true)
})
@XmlRootElement
@XmlAccessorType(XmlAccessType.PROPERTY)
public class PkgData implements Serializable {
@EmbeddedId
private PkgId id;
@Getter(onMethod_ = {
@Embedded,
@Column(unique = true)
})
private PkgId pkgId;
private String base;
@Getter(onMethod_ = {
@Id,
@GeneratedValue,
@XmlTransient,
@JsonbTransient
})
private long id;
@Getter(onMethod_ = {
@ManyToOne
})
private PkgBase base;
@Getter(
onMethod_ = {
@Column(length = 1024)
})
private String description;
@Getter(
onMethod_ = {
@Column(length = 1024)
})
private String url;
private Instant buildDate;
private String packager;
@Getter(onMethod_ = {
@ManyToOne
})
private Packager packager;
private long size;
private String license;
@Getter(onMethod_ = {
@ManyToMany,
@JoinTable(name = "PkgData_license")
})
@JsonbTypeSerializer(SetSerializer.class)
private Set<License> license;
private String md5sum;
@Getter(
onMethod_ = {
@Column(length = 16)
})
private byte[] md5sum;
@Getter(
onMethod_ = {
@Column(length = 1024)
})
private String fileName;
@ElementCollection(fetch = FetchType.EAGER)
private Set<String> replaces;
@Getter(onMethod_ = {
@ManyToMany,
@JoinTable(name = "PkgData_replaces")
})
@JsonbTypeSerializer(SetSerializer.class)
private Set<Dependency> replaces;
@ElementCollection(fetch = FetchType.EAGER)
private Set<String> conflict;
@Getter(onMethod_ = {
@ManyToMany,
@JoinTable(name = "PkgData_conflict")
})
@JsonbTypeSerializer(SetSerializer.class)
private Set<Dependency> conflict;
@ElementCollection(fetch = FetchType.EAGER)
private Set<String> provides;
@Getter(onMethod_ = {
@ManyToMany,
@JoinTable(name = "PkgData_provides")
})
@JsonbTypeSerializer(SetSerializer.class)
private Set<Dependency> provides;
@ElementCollection(fetch = FetchType.EAGER)
private Set<String> depend;
@Getter(onMethod_ = {
@ManyToMany,
@JoinTable(name = "PkgData_depend")
})
@JsonbTypeSerializer(SetSerializer.class)
private Set<Dependency> depend;
@ElementCollection(fetch = FetchType.EAGER)
private Set<String> optdepend;
@Getter(onMethod_ = {
@ManyToMany,
@JoinTable(name = "PkgData_optdepend")
})
@JsonbTypeSerializer(SetSerializer.class)
private Set<Dependency> optdepend;
@ElementCollection(fetch = FetchType.EAGER)
private Set<String> makedepend;
@Getter(onMethod_ = {
@ManyToMany,
@JoinTable(name = "PkgData_makedepend")
})
@JsonbTypeSerializer(SetSerializer.class)
private Set<Dependency> makedepend;
@ElementCollection(fetch = FetchType.EAGER)
private Set<String> makeopkgopt;
@Getter(onMethod_ = {
@ManyToMany,
@JoinTable(name = "PkgData_makepkgopt"),
})
@JsonbTypeSerializer(SetSerializer.class)
private Set<Dependency> makepkgopt;
@ElementCollection(fetch = FetchType.EAGER)
private Set<String> backup;
@Getter(onMethod_ = {
@ManyToMany,
@JoinTable(name = "PkgData_backup"),
})
@JsonbTypeSerializer(SetSerializer.class)
private Set<Dependency> backup;
@XmlTransient
@JsonbTransient
@@ -96,5 +168,19 @@ public class PkgData implements Serializable {
private void writeTimestamp() {
updTimestamp = Instant.now();
}
@Override
public int hashCode() {
return pkgId.hashCode();
}
@Override
public boolean equals(Object obj) {
if (obj instanceof PkgData other) {
return Objects.equals(id, other.id);
} else {
return false;
}
}
}

View File

@@ -2,6 +2,7 @@ package net.woggioni.jpacrepo.api.model;
import jakarta.persistence.Access;
import jakarta.persistence.AccessType;
import jakarta.persistence.Column;
import jakarta.persistence.Embeddable;
import jakarta.persistence.EnumType;
import jakarta.persistence.Enumerated;
@@ -9,21 +10,41 @@ import jakarta.xml.bind.annotation.XmlAccessType;
import jakarta.xml.bind.annotation.XmlAccessorType;
import jakarta.xml.bind.annotation.XmlRootElement;
import lombok.Data;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import java.io.Serializable;
import java.util.Objects;
@Data
@Embeddable
@Access(AccessType.FIELD)
@Access(AccessType.PROPERTY)
@XmlRootElement
@XmlAccessorType(XmlAccessType.PROPERTY)
public class PkgId implements Serializable {
@Getter(
onMethod_ = {
@Column(length = 64)
})
private String name;
@Getter(
onMethod_ = {
@Column(length = 64)
})
private String version;
@Getter(
onMethod_ = {
@Column(length = 16)
})
private String arch;
@Enumerated(EnumType.ORDINAL)
@Getter(
onMethod_ = {
@Enumerated(EnumType.ORDINAL)
})
private CompressionFormat compressionFormat;
}

View File

@@ -15,6 +15,7 @@ import java.io.InputStream;
import java.util.Collection;
import java.util.List;
import java.util.NavigableMap;
import java.util.Optional;
import java.util.Set;
@Remote
@@ -41,7 +42,7 @@ public interface PacmanServiceRemote {
CompressionFormat compressionFormat);
@Nullable
PkgData getPackage(PkgId pkgId);
Optional<PkgData> getPackage(PkgId pkgId);
@Nullable
Long getFileSize(String fileName);

View File

@@ -0,0 +1,35 @@
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.PkgId;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
@XmlRootElement(name = "pkgIds")
@XmlAccessorType(XmlAccessType.PROPERTY)
public class PkgIdList extends ArrayList<PkgId> {
public PkgIdList() {}
public PkgIdList(Collection<PkgId> c) {
super(c);
}
public PkgIdList(PkgId... elements) {
for (PkgId el : elements) add(el);
}
@XmlElement(name = "pkgId")
public List<PkgId> getItems() {
return this;
}
public void setItems(List<PkgId> pkgs) {
this.clear();
this.addAll(pkgs);
}
}

View File

View File

@@ -0,0 +1,11 @@
package net.woggioni.jpacrepo.experimental;
import org.junit.jupiter.api.Test;
public class JPQLTest {
@Test
public void test() {
}
}

View File

@@ -4,9 +4,9 @@ plugins {
dependencies {
compileOnly catalog.jakarta.persistence.api
compileOnly catalog.slf4j.api
implementation catalog.xz
implementation catalog.slf4j.api
implementation catalog.jzstd
implementation catalog.jwo
implementation catalog.commons.compress

View File

@@ -4,6 +4,7 @@ module net.woggioni.jpacrepo.impl {
requires net.woggioni.jpacrepo.api;
requires net.woggioni.jwo;
requires net.woggioni.jzstd;
requires org.slf4j;
requires org.apache.commons.compress;
exports net.woggioni.jpacrepo.impl.model;

View File

@@ -1,164 +0,0 @@
package net.woggioni.jpacrepo.impl.model;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import lombok.SneakyThrows;
import net.woggioni.jpacrepo.api.model.PkgData;
import net.woggioni.jpacrepo.api.model.PkgId;
import net.woggioni.jwo.CollectionUtils;
import net.woggioni.jwo.Fun;
import net.woggioni.jwo.Hash;
import net.woggioni.jwo.JWO;
import net.woggioni.jwo.Tuple2;
import net.woggioni.jwo.UncloseableInputStream;
import net.woggioni.jzstd.ZstdInputStream;
import org.apache.commons.compress.archivers.tar.TarArchiveInputStream;
import org.apache.commons.compress.compressors.xz.XZCompressorInputStream;
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.file.Files;
import java.nio.file.Path;
import java.text.ParseException;
import java.time.Instant;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.TreeMap;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.zip.GZIPInputStream;
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class PkgDataImpl {
@SneakyThrows
public static PkgData parseFile(Path file, net.woggioni.jpacrepo.api.model.CompressionFormat compressionFormat) {
Fun<InputStream, InputStream> decompressorStreamConstructor;
switch (compressionFormat) {
case XZ:
decompressorStreamConstructor = XZCompressorInputStream::new;
break;
case Z_STANDARD:
decompressorStreamConstructor = ZstdInputStream::from;
break;
case GZIP:
decompressorStreamConstructor = GZIPInputStream::new;
break;
default:
throw JWO.newThrowable(ParseException.class,
"Unsupported compression format '%s'", compressionFormat);
}
try(TarArchiveInputStream is = new TarArchiveInputStream(
decompressorStreamConstructor.apply(
new BufferedInputStream(
Files.newInputStream(file))))) {
var archiveEntry = is.getNextEntry();
while (archiveEntry != null) {
if (Objects.equals(".PKGINFO", archiveEntry.getName())) {
try(BufferedReader reader =
new BufferedReader(
new InputStreamReader(
new UncloseableInputStream(is)))) {
Map<String, List<String>> metadata = reader.lines().map(String::trim)
.filter(Predicate.not(String::isEmpty))
.filter(line -> !line.startsWith("#"))
.map((Fun<String, Tuple2<String, String>>) line -> {
int equals = line.indexOf("=");
if (equals < 0) {
throw JWO.newThrowable(ParseException.class,
"Error parsing .PKGINFO file in '%s'", file);
} else {
return Tuple2.newInstance(
line.substring(0, equals).trim(),
line.substring(equals + 1).trim());
}
}).collect(
Collectors.groupingBy(
Tuple2<String, String>::get_1,
TreeMap::new,
Collectors.mapping(Tuple2<String, String>::get_2,
Collectors.toUnmodifiableList())));
PkgData data = new PkgData();
data.setId(new PkgId());
data.getId().setCompressionFormat(compressionFormat);
for (Map.Entry<String, List<String>> entry : metadata.entrySet()) {
String key = entry.getKey();
List<String> value = entry.getValue();
switch (key) {
case "size":
data.setSize(Long.parseLong(value.get(0)));
break;
case "arch":
data.getId().setArch(value.get(0));
break;
case "replaces":
data.setReplaces(value.stream().collect(CollectionUtils.toUnmodifiableTreeSet()));
break;
case "packager":
data.setPackager(value.get(0));
break;
case "url":
data.setUrl(value.get(0));
break;
case "pkgname":
data.getId().setName(value.get(0));
break;
case "builddate":
data.setBuildDate(
Instant.ofEpochSecond(Long.parseLong(value.get(0))));
break;
case "license":
data.setLicense(value.get(0));
break;
case "pkgver":
data.getId().setVersion(value.get(0));
break;
case "pkgdesc":
data.setDescription(value.get(0));
break;
case "provides":
data.setProvides(value.stream().collect(CollectionUtils.toUnmodifiableTreeSet()));
break;
case "conflict":
data.setConflict(value.stream().collect(CollectionUtils.toUnmodifiableTreeSet()));
break;
case "backup":
data.setBackup(value.stream().collect(CollectionUtils.toUnmodifiableTreeSet()));
break;
case "optdepend":
data.setOptdepend(value.stream().collect(CollectionUtils.toUnmodifiableTreeSet()));
break;
case "depend":
data.setDepend(value.stream().collect(CollectionUtils.toUnmodifiableTreeSet()));
break;
case "makedepend":
data.setMakedepend(value.stream().collect(CollectionUtils.toUnmodifiableTreeSet()));
break;
case "makepkgopt":
data.setMakeopkgopt(value.stream().collect(CollectionUtils.toUnmodifiableTreeSet()));
break;
case "pkgbase":
data.setBase(value.get(0));
break;
default:
break;
}
}
try(InputStream fis = Files.newInputStream(file)) {
data.setMd5sum(Hash.hash(Hash.Algorithm.MD5, fis).toString());
}
data.setFileName(file.getFileName().toString());
return data;
}
} else {
archiveEntry = is.getNextEntry();
}
}
throw JWO.newThrowable(ParseException.class, ".PKGINFO file not found in '%s'", file);
}
}
}

View File

@@ -0,0 +1,296 @@
package net.woggioni.jpacrepo.impl.model;
import jakarta.persistence.EntityManager;
import lombok.AccessLevel;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import net.woggioni.jpacrepo.api.model.CompressionFormat;
import net.woggioni.jpacrepo.api.model.Dependency;
import net.woggioni.jpacrepo.api.model.License;
import net.woggioni.jpacrepo.api.model.NamedEntity;
import net.woggioni.jpacrepo.api.model.NamedEntity_;
import net.woggioni.jpacrepo.api.model.Packager;
import net.woggioni.jpacrepo.api.model.PkgBase;
import net.woggioni.jpacrepo.api.model.PkgData;
import net.woggioni.jpacrepo.api.model.PkgId;
import net.woggioni.jwo.CollectionUtils;
import net.woggioni.jwo.Fun;
import net.woggioni.jwo.Hash;
import net.woggioni.jwo.JWO;
import net.woggioni.jwo.Tuple2;
import net.woggioni.jwo.UncloseableInputStream;
import net.woggioni.jzstd.ZstdInputStream;
import org.apache.commons.compress.archivers.tar.TarArchiveInputStream;
import org.apache.commons.compress.compressors.xz.XZCompressorInputStream;
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.file.Files;
import java.nio.file.Path;
import java.text.ParseException;
import java.time.Instant;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.TreeMap;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.zip.GZIPInputStream;
@Slf4j
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
class NamedEntityFinder<T extends NamedEntity> {
private final Map<String, T> cache;
private final EntityManager em;
private final Class<T> cls;
private final Function<String, T> ctor;
public NamedEntityFinder(EntityManager em, Class<T> cls, Function<String, T> ctor) {
this(createLruCache(0x40000), em, cls, ctor);
}
private static <K, V> Map<K, V> createLruCache(int maxSize) {
return new LinkedHashMap<>() {
@Override
protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
return size() >= maxSize;
}
};
}
private Optional<T> queryNamedEntity(String name) {
if(log.isDebugEnabled()) {
log.debug("Querying named entity '{}' with name {}", cls.getName(), name);
}
var cb = em.getCriteriaBuilder();
var tq = cb.createQuery(cls);
var root = tq.from(cls);
tq.select(root).where(cb.equal(root.get(NamedEntity_.NAME), name));
var query = em.createQuery(tq);
query.setMaxResults(1);
return Optional.of(query.getResultList())
.filter(JWO.not(List::isEmpty))
.map(it -> it.get(0));
}
public T getByName(String name) {
return
cache.computeIfAbsent(
name,
it -> queryNamedEntity(it)
.orElseGet(() -> {
var newEntity = ctor.apply(it);
em.persist(newEntity);
return newEntity;
})
);
}
}
public class PkgDataParser {
private final NamedEntityFinder<Dependency> dependencyFinder;
private final NamedEntityFinder<Packager> packagerFinder;
private final NamedEntityFinder<License> licenseFinder;
private final NamedEntityFinder<PkgBase> pkgBaseFinder;
public PkgDataParser(EntityManager em) {
dependencyFinder = new NamedEntityFinder<>(em, Dependency.class, Dependency::of);
packagerFinder = new NamedEntityFinder<>(em, Packager.class, Packager::of);
licenseFinder = new NamedEntityFinder<>(em, License.class, License::of);
pkgBaseFinder = new NamedEntityFinder<>(em, PkgBase.class, PkgBase::of);
}
private static <T extends NamedEntity> T hydrate(
NamedEntityFinder<T> namedEntityFinder, T entity
) {
return Optional.ofNullable(entity)
.map(NamedEntity::getName)
.map(namedEntityFinder::getByName)
.orElse(null);
}
private static <T extends NamedEntity> Set<T> hydrate(
NamedEntityFinder<T> namedEntityFinder, Set<T> entites) {
return entites
.stream()
.map(it -> hydrate(namedEntityFinder, it))
.filter(Objects::nonNull)
.collect(Collectors.toUnmodifiableSet());
}
public PkgData hydrateJPA(PkgData pkgData) {
pkgData.setBase(hydrate(pkgBaseFinder, pkgData.getBase()));
pkgData.setDepend(hydrate(dependencyFinder, pkgData.getDepend()));
pkgData.setOptdepend(hydrate(dependencyFinder, pkgData.getOptdepend()));
pkgData.setProvides(hydrate(dependencyFinder, pkgData.getProvides()));
pkgData.setReplaces(hydrate(dependencyFinder, pkgData.getReplaces()));
pkgData.setBackup(hydrate(dependencyFinder, pkgData.getBackup()));
pkgData.setConflict(hydrate(dependencyFinder, pkgData.getConflict()));
pkgData.setMakedepend(hydrate(dependencyFinder, pkgData.getMakedepend()));
pkgData.setMakepkgopt(hydrate(dependencyFinder, pkgData.getMakepkgopt()));
pkgData.setPackager(hydrate(packagerFinder, pkgData.getPackager()));
pkgData.setLicense(hydrate(licenseFinder, pkgData.getLicense()));
return pkgData;
}
@SneakyThrows
public static PkgData parseFile(Path file, CompressionFormat compressionFormat) {
Fun<InputStream, InputStream> decompressorStreamConstructor = switch (compressionFormat) {
case XZ -> XZCompressorInputStream::new;
case Z_STANDARD -> ZstdInputStream::from;
case GZIP -> GZIPInputStream::new;
default -> throw JWO.newThrowable(ParseException.class,
"Unsupported compression format '%s'", compressionFormat);
};
try (TarArchiveInputStream is = new TarArchiveInputStream(
decompressorStreamConstructor.apply(
new BufferedInputStream(
Files.newInputStream(file))))) {
var archiveEntry = is.getNextEntry();
while (archiveEntry != null) {
if (Objects.equals(".PKGINFO", archiveEntry.getName())) {
try (BufferedReader reader =
new BufferedReader(
new InputStreamReader(
new UncloseableInputStream(is)))) {
Map<String, List<String>> metadata = reader.lines().map(String::trim)
.filter(Predicate.not(String::isEmpty))
.filter(line -> !line.startsWith("#"))
.map((Fun<String, Tuple2<String, String>>) line -> {
int equals = line.indexOf("=");
if (equals < 0) {
throw JWO.newThrowable(ParseException.class,
"Error parsing .PKGINFO file in '%s'", file);
} else {
return Tuple2.newInstance(
line.substring(0, equals).trim(),
line.substring(equals + 1).trim());
}
}).collect(
Collectors.groupingBy(
Tuple2<String, String>::get_1,
TreeMap::new,
Collectors.mapping(Tuple2<String, String>::get_2,
Collectors.toUnmodifiableList())));
PkgData data = new PkgData();
data.setPkgId(new PkgId());
data.getPkgId().setCompressionFormat(compressionFormat);
data.setDepend(Collections.emptySet());
data.setOptdepend(Collections.emptySet());
data.setMakedepend(Collections.emptySet());
data.setMakepkgopt(Collections.emptySet());
data.setProvides(Collections.emptySet());
data.setConflict(Collections.emptySet());
data.setLicense(Collections.emptySet());
data.setReplaces(Collections.emptySet());
data.setBackup(Collections.emptySet());
for (Map.Entry<String, List<String>> entry : metadata.entrySet()) {
String key = entry.getKey();
List<String> value = entry.getValue();
switch (key) {
case "size":
data.setSize(Long.parseLong(value.get(0)));
break;
case "arch":
data.getPkgId().setArch(value.get(0));
break;
case "replaces":
data.setReplaces(value.stream()
.map(Dependency::of)
.collect(CollectionUtils.toUnmodifiableTreeSet()));
break;
case "packager":
data.setPackager(Packager.of(value.get(0)));
break;
case "url":
data.setUrl(value.get(0));
break;
case "pkgname":
data.getPkgId().setName(value.get(0));
break;
case "builddate":
data.setBuildDate(
Instant.ofEpochSecond(Long.parseLong(value.get(0))));
break;
case "license":
data.setLicense(value.stream()
.map(License::of)
.collect(CollectionUtils.toUnmodifiableTreeSet()));
break;
case "pkgver":
data.getPkgId().setVersion(value.get(0));
break;
case "pkgdesc":
data.setDescription(value.get(0));
break;
case "provides":
data.setProvides(value.stream()
.map(Dependency::of)
.collect(CollectionUtils.toUnmodifiableTreeSet()));
break;
case "conflict":
data.setConflict(value
.stream()
.map(Dependency::of)
.collect(CollectionUtils.toUnmodifiableTreeSet()));
break;
case "backup":
data.setBackup(value
.stream()
.map(Dependency::of)
.collect(CollectionUtils.toUnmodifiableTreeSet()));
break;
case "optdepend":
data.setOptdepend(value
.stream()
.map(Dependency::of)
.collect(CollectionUtils.toUnmodifiableTreeSet()));
break;
case "depend":
data.setDepend(value.stream()
.map(Dependency::of)
.collect(CollectionUtils.toUnmodifiableTreeSet()));
break;
case "makedepend":
data.setMakedepend(value
.stream()
.map(Dependency::of)
.collect(CollectionUtils.toUnmodifiableTreeSet()));
break;
case "makepkgopt":
data.setMakepkgopt(value
.stream()
.map(Dependency::of)
.collect(CollectionUtils.toUnmodifiableTreeSet()));
break;
case "pkgbase":
data.setBase(PkgBase.of(value.get(0)));
break;
default:
break;
}
}
try (InputStream fis = Files.newInputStream(file)) {
data.setMd5sum(Hash.hash(Hash.Algorithm.MD5, fis).getBytes());
}
data.setFileName(file.getFileName().toString());
return data;
}
} else {
archiveEntry = is.getNextEntry();
}
}
throw JWO.newThrowable(ParseException.class, ".PKGINFO file not found in '%s'", file);
}
}
}

View File

@@ -9,6 +9,8 @@ open module net.woggioni.jpacrepo {
requires static jakarta.cdi;
requires static jakarta.ws.rs;
requires liquibase.core;
requires liquibase.jakarta.cdi;
requires net.woggioni.jwo;
requires net.woggioni.jpacrepo.impl;
requires org.slf4j;

View File

@@ -0,0 +1,49 @@
package net.woggioni.jpacrepo.factory;
import jakarta.annotation.Resource;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.enterprise.inject.Produces;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import liquibase.integration.jakarta.cdi.CDILiquibaseConfig;
import liquibase.integration.jakarta.cdi.annotations.LiquibaseType;
import liquibase.resource.ClassLoaderResourceAccessor;
import liquibase.resource.ResourceAccessor;
import lombok.SneakyThrows;
@ApplicationScoped
public class LiquibaseFactory {
@Resource
private DataSource myDataSource;
@Produces
@LiquibaseType
public CDILiquibaseConfig createConfig() {
CDILiquibaseConfig config = new CDILiquibaseConfig();
config.setChangeLog("/META-INF/liquibase/jpacrepo.xml");
config.setDefaultSchema("jpacrepo");
config.setShouldRun(true);
return config;
}
@Produces
@LiquibaseType
@SneakyThrows
public DataSource createDataSource() {
Connection conn = myDataSource.getConnection();
Statement stmt = conn.createStatement();
stmt.execute("CREATE SCHEMA IF NOT EXISTS \"jpacrepo\";");
return myDataSource;
}
@Produces
@LiquibaseType
public ResourceAccessor create() {
return new ClassLoaderResourceAccessor(getClass().getClassLoader());
}
}

View File

@@ -1,22 +1,39 @@
package net.woggioni.jpacrepo.factory;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.enterprise.context.RequestScoped;
import jakarta.enterprise.inject.Default;
import jakarta.enterprise.inject.Disposes;
import jakarta.enterprise.inject.Produces;
import jakarta.persistence.EntityManager;
import jakarta.persistence.EntityManagerFactory;
import jakarta.persistence.Persistence;
import net.woggioni.jpacrepo.config.AppConfig;
import java.util.Properties;
@ApplicationScoped
//@ApplicationScoped
public class PersistenceUnitFactory {
@Produces
private EntityManagerFactory createEntityManagerFactory(AppConfig appConfig) {
Properties properties = new Properties();
properties.put("jakarta.persistence.schema-generation.database.action",
appConfig.getInitialSchemaAction().getValue());
properties.put("jakarta.persistence.jtaDataSource", appConfig.getDataSourceJndi());
return Persistence.createEntityManagerFactory("jpacrepo_pu", properties);
}
//
// @Produces
// private EntityManagerFactory createEntityManagerFactory(AppConfig appConfig) {
// Properties properties = new Properties();
// properties.put("jakarta.persistence.schema-generation.database.action",
// appConfig.getInitialSchemaAction().getValue());
// properties.put("jakarta.persistence.jtaDataSource", appConfig.getDataSourceJndi());
// return Persistence.createEntityManagerFactory("jpacrepo_pu", properties);
// }
//
// @Produces
// @Default
// @RequestScoped
// public EntityManager create(EntityManagerFactory emf) {
// return emf.createEntityManager();
// }
//
// public void dispose(@Disposes @Default EntityManager entityManager) {
// if (entityManager.isOpen()) {
// entityManager.close();
// }
// }
}

View File

@@ -11,7 +11,7 @@ import jakarta.ejb.Lock;
import jakarta.ejb.LockType;
import jakarta.ejb.Remote;
import jakarta.ejb.Schedule;
import jakarta.ejb.Stateless;
import jakarta.ejb.Singleton;
import jakarta.ejb.TransactionAttribute;
import jakarta.ejb.TransactionAttributeType;
import jakarta.ejb.TransactionManagement;
@@ -30,12 +30,13 @@ import net.woggioni.jpacrepo.api.wire.PkgTuple;
import net.woggioni.jpacrepo.cache.PackageCache;
import net.woggioni.jpacrepo.config.AppConfig;
import net.woggioni.jpacrepo.impl.model.CompressionFormatImpl;
import net.woggioni.jpacrepo.impl.model.PkgDataImpl;
import net.woggioni.jpacrepo.impl.model.PkgDataParser;
import net.woggioni.jpacrepo.persistence.QueryEngine;
import net.woggioni.jpacrepo.service.jpa.Queries;
import net.woggioni.jpacrepo.version.PkgIdComparator;
import net.woggioni.jwo.CollectionUtils;
import net.woggioni.jwo.Con;
import net.woggioni.jwo.Hash;
import net.woggioni.jwo.JWO;
import net.woggioni.jwo.Sup;
import net.woggioni.jwo.Tuple2;
@@ -63,7 +64,9 @@ import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@Stateless
import static java.util.function.Predicate.not;
@Singleton
@Lock(LockType.READ)
@TransactionManagement(TransactionManagementType.CONTAINER)
@ConcurrencyManagement(ConcurrencyManagementType.CONTAINER)
@@ -71,7 +74,7 @@ import java.util.stream.Stream;
@Remote({PacmanServiceRemote.class})
public class PacmanServiceEJB implements PacmanServiceLocal {
@PersistenceContext
@PersistenceContext(name = "jpacrepo_pu")
private EntityManager em;
@Inject
@@ -123,9 +126,10 @@ public class PacmanServiceEJB implements PacmanServiceLocal {
});
long[] count = new long[]{0};
long totalPackages = fileListStreamSupplier.get().count();
var parser = new PkgDataParser(em);
Con<Boolean> persistPackages = (Boolean drain) -> {
while ((drain && inProgress.size() > 0) || inProgress.size() > maxInProgress) {
while ((drain && !inProgress.isEmpty()) || inProgress.size() > maxInProgress) {
Optional.ofNullable(completionService.poll(1, TimeUnit.SECONDS))
.ifPresent((Con<Future<PkgData>>) future -> {
inProgress.remove(future);
@@ -135,7 +139,7 @@ public class PacmanServiceEJB implements PacmanServiceLocal {
} catch (ExecutionException ee) {
throw ee.getCause();
}
persistPackage(em, pkgData, ++count[0], totalPackages);
persistPackage(em, parser, pkgData, ++count[0], totalPackages);
});
}
};
@@ -146,7 +150,11 @@ public class PacmanServiceEJB implements PacmanServiceLocal {
}).get()) {
inProgress.add(completionService.submit(() -> {
try {
return PkgDataImpl.parseFile(file, CompressionFormatImpl.guess(file));
var pkgData = PkgDataParser.parseFile(file, CompressionFormatImpl.guess(file));
if(logger.isDebugEnabled()) {
logger.debug("Parsed package file {}", file);
}
return pkgData;
} catch (Exception ex) {
logger.error(String.format("Error parsing '%s'", file.toAbsolutePath()), ex);
throw ex;
@@ -162,12 +170,12 @@ public class PacmanServiceEJB implements PacmanServiceLocal {
packageCache.invalidateCache();
}
private void persistPackage(EntityManager em, PkgData pkgData, long count, long totalPackages) {
private void persistPackage(EntityManager em, PkgDataParser parser, 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);
em.persist(parser.hydrateJPA(pkgData));
logger.info("({}/{}) Persisting package {}", count, totalPackages, pkgData.getFileName());
}
}
@@ -231,7 +239,7 @@ public class PacmanServiceEJB implements PacmanServiceLocal {
@Override
public List<PkgData> searchByHash(@Nonnull String hash) {
return Queries.searchPackagesByHash(em, hash).getResultList();
return Queries.searchPackagesByHash(em, Hash.hexToBytes(hash)).getResultList();
}
@Override
@@ -241,7 +249,9 @@ public class PacmanServiceEJB implements PacmanServiceLocal {
@Override
public List<String> listHashes() {
return Queries.listHashes(em).getResultList();
return Queries.listHashes(em)
.getResultStream().map(JWO::bytesToHex)
.toList();
}
@Override
@@ -278,8 +288,7 @@ public class PacmanServiceEJB implements PacmanServiceLocal {
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);
;
String md5sum = JWO.bytesToHex(tuple.get(3, byte[].class));
PkgTuple pkgTuple = new PkgTuple();
pkgTuple.setFileName(filename);
pkgTuple.setSize(size);
@@ -296,22 +305,26 @@ public class PacmanServiceEJB implements PacmanServiceLocal {
@Nullable
@Override
public PkgData getPackage(PkgId pkgId) {
return em.find(PkgData.class, pkgId);
public Optional<PkgData> getPackage(PkgId pkgId) {
var query = Queries.getPackageById(em, pkgId);
query.setMaxResults(1);
return Optional.of(query.getResultList())
.filter(not(List::isEmpty))
.map(l -> l.get(0));
}
@SneakyThrows
public boolean addPackage(String fileName, InputStream input) {
java.nio.file.Path file = Files.createTempFile(ctx.getRepoFolder(), fileName, null);
List<PkgData> savedFiles = searchByFileName(fileName);
if (savedFiles.size() > 0) return false;
if (!savedFiles.isEmpty()) return false;
else {
try (OutputStream output = Files.newOutputStream(file)) {
JWO.copy(input, output, 0x10000);
PkgData pkg = PkgDataImpl.parseFile(file,
PkgData pkg = PkgDataParser.parseFile(file,
CompressionFormatImpl.guess(Paths.get(fileName)));
pkg.setFileName(fileName);
Optional.ofNullable(em.find(PkgData.class, pkg.getId())).ifPresent((Con<PkgData>) (pkgData -> {
getPackage(pkg.getPkgId()).ifPresent((Con<PkgData>) (pkgData -> {
em.remove(pkgData);
Files.delete(ctx.getRepoFolder().resolve(pkgData.getFileName()));
}));

View File

@@ -39,6 +39,7 @@ import net.woggioni.jpacrepo.api.model.PkgId;
import net.woggioni.jpacrepo.api.security.Roles;
import net.woggioni.jpacrepo.api.service.PacmanServiceLocal;
import net.woggioni.jpacrepo.api.wire.PkgDataList;
import net.woggioni.jpacrepo.api.wire.PkgIdList;
import net.woggioni.jpacrepo.api.wire.PkgTuple;
import net.woggioni.jpacrepo.api.wire.StringList;
import net.woggioni.jpacrepo.config.AppConfig;
@@ -121,7 +122,9 @@ public class PacmanWebService {
@QueryParam("arch") String arch,
@QueryParam("compressionFormat") CompressionFormat compressionFormat
) {
return Response.ok(service.searchPkgId(name, version, arch, compressionFormat)).build();
return Response.ok(
new PkgIdList(service.searchPkgId(name, version, arch, compressionFormat))
).build();
}
@GET

View File

@@ -1,5 +1,6 @@
package net.woggioni.jpacrepo.service.jpa;
import jakarta.persistence.EntityGraph;
import jakarta.persistence.EntityManager;
import jakarta.persistence.Tuple;
import jakarta.persistence.TypedQuery;
@@ -26,6 +27,7 @@ import java.util.Optional;
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class Queries {
private static final String ENTITY_GRAPH_PROPERTY = "jakarta.persistence.fetchgraph";
private interface PredicateSupplier<T> {
Predicate get(CriteriaBuilder cb, Root<T> root);
}
@@ -47,7 +49,9 @@ public class Queries {
Root<PkgData> root = criteriaQuery.from(entity);
Predicate predicate = cb.equal(root.get(PkgData_.fileName), fileName);
criteriaQuery.select(root).where(predicate);
return em.createQuery(criteriaQuery);
var query = em.createQuery(criteriaQuery);
query.setHint(ENTITY_GRAPH_PROPERTY, getPkgDataEntityGraph(em));
return query;
}
public static TypedQuery<Instant> getUpdateTimestampByFileName(EntityManager em, String fileName) {
@@ -72,7 +76,7 @@ public class Queries {
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);
Path<PkgId> pkgIdPathSub = pkgDataRootSub.get(PkgData_.pkgId);
Predicate havingPredicate = cb.greaterThan(cb.count(
pkgIdPathSub.get(PkgId_.version)), minNumberOfDifferentVersions);
subQuery.select(pkgIdPathSub.get(PkgId_.name))
@@ -82,7 +86,7 @@ public class Queries {
).having(havingPredicate);
Predicate predicate = cb.and(
cb.lessThan(pkgDataRoot.get(PkgData_.buildDate), cutoff),
pkgDataRoot.get(PkgData_.id).get(PkgId_.name).in(subQuery.getSelection())
pkgDataRoot.get(PkgData_.pkgId).get(PkgId_.name).in(subQuery.getSelection())
);
criteriaQuery.select(pkgDataRoot.get(PkgData_.fileName))
.where(predicate)
@@ -90,7 +94,7 @@ public class Queries {
return em.createQuery(criteriaQuery);
}
public static TypedQuery<Long> countPackagesByHash(EntityManager em, String hash) {
public static TypedQuery<Long> countPackagesByHash(EntityManager em, byte[] hash) {
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Long> criteriaQuery = cb.createQuery(Long.class);
Metamodel metamodel = em.getMetamodel();
@@ -109,10 +113,12 @@ public class Queries {
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);
var query = em.createQuery(criteriaQuery);
query.setHint(ENTITY_GRAPH_PROPERTY, getPkgDataEntityGraph(em));
return query;
}
public static TypedQuery<PkgData> searchPackagesByHash(EntityManager em, String hash) {
public static TypedQuery<PkgData> searchPackagesByHash(EntityManager em, byte[] hash) {
return searchPackagesByPredicate(em, (cb, root) -> cb.equal(root.get(PkgData_.md5sum), hash));
}
@@ -131,13 +137,28 @@ public class Queries {
return em.createQuery(criteriaQuery);
}
public static TypedQuery<PkgData> getPackageById(EntityManager em, PkgId pkgId) {
var cb = em.getCriteriaBuilder();
var cq = cb.createQuery(PkgData.class);
var root = cq.from(PkgData_.class_);
cq.select(root).where(
cb.equal(
root.get(PkgData_.pkgId),
pkgId
)
);
var query = em.createQuery(cq);
query.setHint(ENTITY_GRAPH_PROPERTY, getPkgDataEntityGraph(em));
return query;
}
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);
Path<PkgId> pkgIdPath = root.get(PkgData_.pkgId);
Predicate predicate = cb.like(
cb.lower(pkgIdPath.get(PkgId_.name)),
"%%" + needle + "%%"
@@ -159,9 +180,9 @@ public class Queries {
return em.createQuery(criteriaQuery);
}
public static TypedQuery<String> listHashes(EntityManager em) {
public static TypedQuery<byte[]> listHashes(EntityManager em) {
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<String> criteriaQuery = cb.createQuery(String.class);
CriteriaQuery<byte[]> criteriaQuery = cb.createQuery(byte[].class);
Metamodel metamodel = em.getMetamodel();
EntityType<PkgData> entity = metamodel.entity(PkgData.class);
Root<PkgData> root = criteriaQuery.from(entity);
@@ -180,7 +201,7 @@ public class Queries {
Metamodel metamodel = em.getMetamodel();
EntityType<PkgData> entity = metamodel.entity(PkgData.class);
Root<PkgData> root = criteriaQuery.from(entity);
Path<PkgId> pkgIdRoot = root.get(PkgData_.id);
Path<PkgId> pkgIdRoot = root.get(PkgData_.pkgId);
Predicate[] predicates = JWO.streamCat(
Optional.ofNullable(name)
.map(it -> cb.equal(pkgIdRoot.get(PkgId_.name), it)).stream(),
@@ -219,7 +240,7 @@ public class Queries {
Metamodel metamodel = em.getMetamodel();
EntityType<PkgData> entity = metamodel.entity(PkgData.class);
Root<PkgData> root = criteriaQuery.from(entity);
Path<PkgId> idPath = root.get(PkgData_.id);
Path<PkgId> idPath = root.get(PkgData_.pkgId);
criteriaQuery.multiselect(
idPath,
root.get(PkgData_.fileName),
@@ -244,7 +265,7 @@ public class Queries {
CriteriaBuilder builder = em.getCriteriaBuilder();
criteriaQuery = builder.createQuery(PkgData.class);
Root<PkgData> entity = criteriaQuery.from(PkgData.class);
Path<PkgId> pkgIdPath = entity.get(PkgData_.id);
Path<PkgId> pkgIdPath = entity.get(PkgData_.pkgId);
Predicate predicate = builder.and(JWO.streamCat(
JWO.optional2Stream(
Optional.ofNullable(name)
@@ -275,7 +296,25 @@ public class Queries {
builder.asc(pkgIdPath.get(PkgId_.compressionFormat)),
builder.asc(entity.get(PkgData_.fileName))
);
return em.createQuery(criteriaQuery);
var query = em.createQuery(criteriaQuery);
query.setHint(ENTITY_GRAPH_PROPERTY, getPkgDataEntityGraph(em));
return query;
}
private static EntityGraph<PkgData> getPkgDataEntityGraph(EntityManager em) {
var graph = em.createEntityGraph(PkgData.class);
graph.addAttributeNodes(PkgData_.base);
graph.addAttributeNodes(PkgData_.packager);
graph.addAttributeNodes(PkgData_.license);
graph.addSubgraph(PkgData_.depend);
graph.addSubgraph(PkgData_.backup);
graph.addSubgraph(PkgData_.conflict);
graph.addSubgraph(PkgData_.replaces);
graph.addSubgraph(PkgData_.makedepend);
graph.addSubgraph(PkgData_.makepkgopt);
graph.addSubgraph(PkgData_.optdepend);
graph.addSubgraph(PkgData_.provides);
return graph;
}
}

View File

@@ -0,0 +1,243 @@
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog" xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext" xmlns:pro="http://www.liquibase.org/xml/ns/pro" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog-ext http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd http://www.liquibase.org/xml/ns/pro http://www.liquibase.org/xml/ns/pro/liquibase-pro-latest.xsd http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-latest.xsd">
<changeSet author="Walter Oggioni &lt;oggioni.walter@gmail.com&gt;" id="1707439864675-1">
<createTable tableName="pkgdata">
<column name="compressionformat" type="SMALLINT"/>
<column name="base_id" type="BIGINT"/>
<column name="builddate" type="TIMESTAMP WITH TIME ZONE"/>
<column name="id" type="BIGINT">
<constraints nullable="false" primaryKey="true" primaryKeyName="pkgdata_pkey"/>
</column>
<column name="packager_id" type="BIGINT"/>
<column name="size" type="BIGINT">
<constraints nullable="false"/>
</column>
<column name="updtimestamp" type="TIMESTAMP WITH TIME ZONE"/>
<column name="arch" type="VARCHAR(16)"/>
<column name="md5sum" type="BYTEA"/>
<column name="version" type="VARCHAR(64)"/>
<column name="name" type="VARCHAR(64)"/>
<column name="description" type="VARCHAR(1024)"/>
<column name="filename" type="VARCHAR(1024)"/>
<column name="url" type="VARCHAR(1024)"/>
</createTable>
</changeSet>
<changeSet author="Walter Oggioni &lt;oggioni.walter@gmail.com&gt;" id="1707439864675-2">
<createTable tableName="dependency">
<column name="id" type="BIGINT">
<constraints nullable="false" primaryKey="true" primaryKeyName="dependency_pkey"/>
</column>
<column name="name" type="VARCHAR(1024)"/>
</createTable>
</changeSet>
<changeSet author="Walter Oggioni &lt;oggioni.walter@gmail.com&gt;" id="1707439864675-3">
<createTable tableName="license">
<column name="id" type="BIGINT">
<constraints nullable="false" primaryKey="true" primaryKeyName="license_pkey"/>
</column>
<column name="name" type="VARCHAR(1024)"/>
</createTable>
</changeSet>
<changeSet author="Walter Oggioni &lt;oggioni.walter@gmail.com&gt;" id="1707439864675-4">
<createTable tableName="packager">
<column name="id" type="BIGINT">
<constraints nullable="false" primaryKey="true" primaryKeyName="packager_pkey"/>
</column>
<column name="name" type="VARCHAR(1024)"/>
</createTable>
</changeSet>
<changeSet author="Walter Oggioni &lt;oggioni.walter@gmail.com&gt;" id="1707439864675-5">
<createTable tableName="pkgbase">
<column name="id" type="BIGINT">
<constraints nullable="false" primaryKey="true" primaryKeyName="pkgbase_pkey"/>
</column>
<column name="name" type="VARCHAR(1024)"/>
</createTable>
</changeSet>
<changeSet author="Walter Oggioni &lt;oggioni.walter@gmail.com&gt;" id="1707439864675-6">
<addUniqueConstraint columnNames="filename" constraintName="pkgdata_filename_key" tableName="pkgdata"/>
</changeSet>
<changeSet author="Walter Oggioni &lt;oggioni.walter@gmail.com&gt;" id="1707439864675-7">
<addUniqueConstraint columnNames="md5sum" constraintName="pkgdata_md5sum_key" tableName="pkgdata"/>
</changeSet>
<changeSet author="Walter Oggioni &lt;oggioni.walter@gmail.com&gt;" id="1707439864675-8">
<addUniqueConstraint columnNames="name, version, arch, compressionformat" constraintName="pkgdata_name_version_arch_compressionformat_key" tableName="pkgdata"/>
</changeSet>
<changeSet author="Walter Oggioni &lt;oggioni.walter@gmail.com&gt;" id="1707439864675-9">
<addUniqueConstraint columnNames="name" constraintName="dependency_name_key" tableName="dependency"/>
</changeSet>
<changeSet author="Walter Oggioni &lt;oggioni.walter@gmail.com&gt;" id="1707439864675-10">
<addUniqueConstraint columnNames="name" constraintName="license_name_key" tableName="license"/>
</changeSet>
<changeSet author="Walter Oggioni &lt;oggioni.walter@gmail.com&gt;" id="1707439864675-11">
<addUniqueConstraint columnNames="name" constraintName="packager_name_key" tableName="packager"/>
</changeSet>
<changeSet author="Walter Oggioni &lt;oggioni.walter@gmail.com&gt;" id="1707439864675-12">
<addUniqueConstraint columnNames="name" constraintName="pkgbase_name_key" tableName="pkgbase"/>
</changeSet>
<changeSet author="Walter Oggioni &lt;oggioni.walter@gmail.com&gt;" id="1707439864675-13">
<createSequence cacheSize="1" cycle="false" dataType="bigint" incrementBy="50" maxValue="9223372036854775807" minValue="1" sequenceName="dependency_seq" startValue="1"/>
</changeSet>
<changeSet author="Walter Oggioni &lt;oggioni.walter@gmail.com&gt;" id="1707439864675-14">
<createSequence cacheSize="1" cycle="false" dataType="bigint" incrementBy="50" maxValue="9223372036854775807" minValue="1" sequenceName="license_seq" startValue="1"/>
</changeSet>
<changeSet author="Walter Oggioni &lt;oggioni.walter@gmail.com&gt;" id="1707439864675-15">
<createSequence cacheSize="1" cycle="false" dataType="bigint" incrementBy="50" maxValue="9223372036854775807" minValue="1" sequenceName="packager_seq" startValue="1"/>
</changeSet>
<changeSet author="Walter Oggioni &lt;oggioni.walter@gmail.com&gt;" id="1707439864675-16">
<createSequence cacheSize="1" cycle="false" dataType="bigint" incrementBy="50" maxValue="9223372036854775807" minValue="1" sequenceName="pkgbase_seq" startValue="1"/>
</changeSet>
<changeSet author="Walter Oggioni &lt;oggioni.walter@gmail.com&gt;" id="1707439864675-17">
<createSequence cacheSize="1" cycle="false" dataType="bigint" incrementBy="50" maxValue="9223372036854775807" minValue="1" sequenceName="pkgdata_seq" startValue="1"/>
</changeSet>
<changeSet author="Walter Oggioni &lt;oggioni.walter@gmail.com&gt;" id="1707439864675-18">
<createTable tableName="pkgdata_backup">
<column name="pkgdata_id" type="BIGINT">
<constraints nullable="false" primaryKey="true" primaryKeyName="pkgdata_backup_pkey"/>
</column>
<column name="backup_id" type="BIGINT">
<constraints nullable="false" primaryKey="true" primaryKeyName="pkgdata_backup_pkey"/>
</column>
</createTable>
</changeSet>
<changeSet author="Walter Oggioni &lt;oggioni.walter@gmail.com&gt;" id="1707439864675-19">
<createTable tableName="pkgdata_conflict">
<column name="pkgdata_id" type="BIGINT">
<constraints nullable="false" primaryKey="true" primaryKeyName="pkgdata_conflict_pkey"/>
</column>
<column name="conflict_id" type="BIGINT">
<constraints nullable="false" primaryKey="true" primaryKeyName="pkgdata_conflict_pkey"/>
</column>
</createTable>
</changeSet>
<changeSet author="Walter Oggioni &lt;oggioni.walter@gmail.com&gt;" id="1707439864675-20">
<createTable tableName="pkgdata_depend">
<column name="pkgdata_id" type="BIGINT">
<constraints nullable="false" primaryKey="true" primaryKeyName="pkgdata_depend_pkey"/>
</column>
<column name="depend_id" type="BIGINT">
<constraints nullable="false" primaryKey="true" primaryKeyName="pkgdata_depend_pkey"/>
</column>
</createTable>
</changeSet>
<changeSet author="Walter Oggioni &lt;oggioni.walter@gmail.com&gt;" id="1707439864675-21">
<createTable tableName="pkgdata_license">
<column name="pkgdata_id" type="BIGINT">
<constraints nullable="false" primaryKey="true" primaryKeyName="pkgdata_license_pkey"/>
</column>
<column name="license_id" type="BIGINT">
<constraints nullable="false" primaryKey="true" primaryKeyName="pkgdata_license_pkey"/>
</column>
</createTable>
</changeSet>
<changeSet author="Walter Oggioni &lt;oggioni.walter@gmail.com&gt;" id="1707439864675-22">
<createTable tableName="pkgdata_makedepend">
<column name="pkgdata_id" type="BIGINT">
<constraints nullable="false" primaryKey="true" primaryKeyName="pkgdata_makedepend_pkey"/>
</column>
<column name="makedepend_id" type="BIGINT">
<constraints nullable="false" primaryKey="true" primaryKeyName="pkgdata_makedepend_pkey"/>
</column>
</createTable>
</changeSet>
<changeSet author="Walter Oggioni &lt;oggioni.walter@gmail.com&gt;" id="1707439864675-23">
<createTable tableName="pkgdata_makepkgopt">
<column name="pkgdata_id" type="BIGINT">
<constraints nullable="false" primaryKey="true" primaryKeyName="pkgdata_makepkgopt_pkey"/>
</column>
<column name="makepkgopt_id" type="BIGINT">
<constraints nullable="false" primaryKey="true" primaryKeyName="pkgdata_makepkgopt_pkey"/>
</column>
</createTable>
</changeSet>
<changeSet author="Walter Oggioni &lt;oggioni.walter@gmail.com&gt;" id="1707439864675-24">
<createTable tableName="pkgdata_optdepend">
<column name="pkgdata_id" type="BIGINT">
<constraints nullable="false" primaryKey="true" primaryKeyName="pkgdata_optdepend_pkey"/>
</column>
<column name="optdepend_id" type="BIGINT">
<constraints nullable="false" primaryKey="true" primaryKeyName="pkgdata_optdepend_pkey"/>
</column>
</createTable>
</changeSet>
<changeSet author="Walter Oggioni &lt;oggioni.walter@gmail.com&gt;" id="1707439864675-25">
<createTable tableName="pkgdata_provides">
<column name="pkgdata_id" type="BIGINT">
<constraints nullable="false" primaryKey="true" primaryKeyName="pkgdata_provides_pkey"/>
</column>
<column name="provides_id" type="BIGINT">
<constraints nullable="false" primaryKey="true" primaryKeyName="pkgdata_provides_pkey"/>
</column>
</createTable>
</changeSet>
<changeSet author="Walter Oggioni &lt;oggioni.walter@gmail.com&gt;" id="1707439864675-26">
<createTable tableName="pkgdata_replaces">
<column name="pkgdata_id" type="BIGINT">
<constraints nullable="false" primaryKey="true" primaryKeyName="pkgdata_replaces_pkey"/>
</column>
<column name="replaces_id" type="BIGINT">
<constraints nullable="false" primaryKey="true" primaryKeyName="pkgdata_replaces_pkey"/>
</column>
</createTable>
</changeSet>
<changeSet author="Walter Oggioni &lt;oggioni.walter@gmail.com&gt;" id="1707439864675-27">
<addForeignKeyConstraint baseColumnNames="conflict_id" baseTableName="pkgdata_conflict" constraintName="fk24nqbo323snpnlwweh6im6r9b" deferrable="false" initiallyDeferred="false" onDelete="NO ACTION" onUpdate="NO ACTION" referencedColumnNames="id" referencedTableName="dependency" validate="true"/>
</changeSet>
<changeSet author="Walter Oggioni &lt;oggioni.walter@gmail.com&gt;" id="1707439864675-28">
<addForeignKeyConstraint baseColumnNames="pkgdata_id" baseTableName="pkgdata_makedepend" constraintName="fk429xi3idno5yap1nlivrnpy06" deferrable="false" initiallyDeferred="false" onDelete="NO ACTION" onUpdate="NO ACTION" referencedColumnNames="id" referencedTableName="pkgdata" validate="true"/>
</changeSet>
<changeSet author="Walter Oggioni &lt;oggioni.walter@gmail.com&gt;" id="1707439864675-29">
<addForeignKeyConstraint baseColumnNames="optdepend_id" baseTableName="pkgdata_optdepend" constraintName="fk4ura4v2u5x16yp8ok6bfvxr4h" deferrable="false" initiallyDeferred="false" onDelete="NO ACTION" onUpdate="NO ACTION" referencedColumnNames="id" referencedTableName="dependency" validate="true"/>
</changeSet>
<changeSet author="Walter Oggioni &lt;oggioni.walter@gmail.com&gt;" id="1707439864675-30">
<addForeignKeyConstraint baseColumnNames="pkgdata_id" baseTableName="pkgdata_provides" constraintName="fk656rbinf6abvk4f982q21i68o" deferrable="false" initiallyDeferred="false" onDelete="NO ACTION" onUpdate="NO ACTION" referencedColumnNames="id" referencedTableName="pkgdata" validate="true"/>
</changeSet>
<changeSet author="Walter Oggioni &lt;oggioni.walter@gmail.com&gt;" id="1707439864675-31">
<addForeignKeyConstraint baseColumnNames="pkgdata_id" baseTableName="pkgdata_conflict" constraintName="fk6et6auii880vcyo8cod6gndsy" deferrable="false" initiallyDeferred="false" onDelete="NO ACTION" onUpdate="NO ACTION" referencedColumnNames="id" referencedTableName="pkgdata" validate="true"/>
</changeSet>
<changeSet author="Walter Oggioni &lt;oggioni.walter@gmail.com&gt;" id="1707439864675-32">
<addForeignKeyConstraint baseColumnNames="backup_id" baseTableName="pkgdata_backup" constraintName="fk6hvpvdhjlyi4qsoyiw4lksae5" deferrable="false" initiallyDeferred="false" onDelete="NO ACTION" onUpdate="NO ACTION" referencedColumnNames="id" referencedTableName="dependency" validate="true"/>
</changeSet>
<changeSet author="Walter Oggioni &lt;oggioni.walter@gmail.com&gt;" id="1707439864675-33">
<addForeignKeyConstraint baseColumnNames="depend_id" baseTableName="pkgdata_depend" constraintName="fkai19aek8k3vau0k15td18uc6h" deferrable="false" initiallyDeferred="false" onDelete="NO ACTION" onUpdate="NO ACTION" referencedColumnNames="id" referencedTableName="dependency" validate="true"/>
</changeSet>
<changeSet author="Walter Oggioni &lt;oggioni.walter@gmail.com&gt;" id="1707439864675-34">
<addForeignKeyConstraint baseColumnNames="pkgdata_id" baseTableName="pkgdata_depend" constraintName="fkci76y22x9o3ytakt6adnc6d8v" deferrable="false" initiallyDeferred="false" onDelete="NO ACTION" onUpdate="NO ACTION" referencedColumnNames="id" referencedTableName="pkgdata" validate="true"/>
</changeSet>
<changeSet author="Walter Oggioni &lt;oggioni.walter@gmail.com&gt;" id="1707439864675-35">
<addForeignKeyConstraint baseColumnNames="base_id" baseTableName="pkgdata" constraintName="fkdbglulawmrf5eanlxpic0370j" deferrable="false" initiallyDeferred="false" onDelete="NO ACTION" onUpdate="NO ACTION" referencedColumnNames="id" referencedTableName="pkgbase" validate="true"/>
</changeSet>
<changeSet author="Walter Oggioni &lt;oggioni.walter@gmail.com&gt;" id="1707439864675-36">
<addForeignKeyConstraint baseColumnNames="pkgdata_id" baseTableName="pkgdata_license" constraintName="fkfbcetjtq920birmewjayj99fd" deferrable="false" initiallyDeferred="false" onDelete="NO ACTION" onUpdate="NO ACTION" referencedColumnNames="id" referencedTableName="pkgdata" validate="true"/>
</changeSet>
<changeSet author="Walter Oggioni &lt;oggioni.walter@gmail.com&gt;" id="1707439864675-37">
<addForeignKeyConstraint baseColumnNames="provides_id" baseTableName="pkgdata_provides" constraintName="fkgcrqlwrv05rh1hcsi56xgkanm" deferrable="false" initiallyDeferred="false" onDelete="NO ACTION" onUpdate="NO ACTION" referencedColumnNames="id" referencedTableName="dependency" validate="true"/>
</changeSet>
<changeSet author="Walter Oggioni &lt;oggioni.walter@gmail.com&gt;" id="1707439864675-38">
<addForeignKeyConstraint baseColumnNames="pkgdata_id" baseTableName="pkgdata_backup" constraintName="fkgiq44wme1akcpdhm2eg3vfp0f" deferrable="false" initiallyDeferred="false" onDelete="NO ACTION" onUpdate="NO ACTION" referencedColumnNames="id" referencedTableName="pkgdata" validate="true"/>
</changeSet>
<changeSet author="Walter Oggioni &lt;oggioni.walter@gmail.com&gt;" id="1707439864675-39">
<addForeignKeyConstraint baseColumnNames="pkgdata_id" baseTableName="pkgdata_optdepend" constraintName="fkkdgyxf9lhh7q5cwytdi9hpdt5" deferrable="false" initiallyDeferred="false" onDelete="NO ACTION" onUpdate="NO ACTION" referencedColumnNames="id" referencedTableName="pkgdata" validate="true"/>
</changeSet>
<changeSet author="Walter Oggioni &lt;oggioni.walter@gmail.com&gt;" id="1707439864675-40">
<addForeignKeyConstraint baseColumnNames="license_id" baseTableName="pkgdata_license" constraintName="fkktcugf8cborm40b75wsupd3lf" deferrable="false" initiallyDeferred="false" onDelete="NO ACTION" onUpdate="NO ACTION" referencedColumnNames="id" referencedTableName="license" validate="true"/>
</changeSet>
<changeSet author="Walter Oggioni &lt;oggioni.walter@gmail.com&gt;" id="1707439864675-41">
<addForeignKeyConstraint baseColumnNames="packager_id" baseTableName="pkgdata" constraintName="fko3oqleprd36mpslc484783ud4" deferrable="false" initiallyDeferred="false" onDelete="NO ACTION" onUpdate="NO ACTION" referencedColumnNames="id" referencedTableName="packager" validate="true"/>
</changeSet>
<changeSet author="Walter Oggioni &lt;oggioni.walter@gmail.com&gt;" id="1707439864675-42">
<addForeignKeyConstraint baseColumnNames="replaces_id" baseTableName="pkgdata_replaces" constraintName="fko7yscxwbb0der580pxqgtkovs" deferrable="false" initiallyDeferred="false" onDelete="NO ACTION" onUpdate="NO ACTION" referencedColumnNames="id" referencedTableName="dependency" validate="true"/>
</changeSet>
<changeSet author="Walter Oggioni &lt;oggioni.walter@gmail.com&gt;" id="1707439864675-43">
<addForeignKeyConstraint baseColumnNames="pkgdata_id" baseTableName="pkgdata_replaces" constraintName="fkqf9a43r0tdhns382ak386bdnr" deferrable="false" initiallyDeferred="false" onDelete="NO ACTION" onUpdate="NO ACTION" referencedColumnNames="id" referencedTableName="pkgdata" validate="true"/>
</changeSet>
<changeSet author="Walter Oggioni &lt;oggioni.walter@gmail.com&gt;" id="1707439864675-44">
<addForeignKeyConstraint baseColumnNames="makepkgopt_id" baseTableName="pkgdata_makepkgopt" constraintName="fkr4wcod9vkiyhey261g6k8f4g6" deferrable="false" initiallyDeferred="false" onDelete="NO ACTION" onUpdate="NO ACTION" referencedColumnNames="id" referencedTableName="dependency" validate="true"/>
</changeSet>
<changeSet author="Walter Oggioni &lt;oggioni.walter@gmail.com&gt;" id="1707439864675-45">
<addForeignKeyConstraint baseColumnNames="pkgdata_id" baseTableName="pkgdata_makepkgopt" constraintName="fks6qck7ato6bnv3okee3461lx6" deferrable="false" initiallyDeferred="false" onDelete="NO ACTION" onUpdate="NO ACTION" referencedColumnNames="id" referencedTableName="pkgdata" validate="true"/>
</changeSet>
<changeSet author="Walter Oggioni &lt;oggioni.walter@gmail.com&gt;" id="1707439864675-46">
<addForeignKeyConstraint baseColumnNames="makedepend_id" baseTableName="pkgdata_makedepend" constraintName="fktkj1w12dtv5fqykgwvvnpwgo" deferrable="false" initiallyDeferred="false" onDelete="NO ACTION" onUpdate="NO ACTION" referencedColumnNames="id" referencedTableName="dependency" validate="true"/>
</changeSet>
</databaseChangeLog>

View File

@@ -5,12 +5,18 @@
version="2.1">
<persistence-unit name="jpacrepo_pu" transaction-type="JTA">
<class>net.woggioni.jpacrepo.api.model.PkgData</class>
<class>net.woggioni.jpacrepo.api.model.PkgId</class>
<class>net.woggioni.jpacrepo.api.model.PkgData</class>
<class>net.woggioni.jpacrepo.api.model.License</class>
<class>net.woggioni.jpacrepo.api.model.PkgBase</class>
<class>net.woggioni.jpacrepo.api.model.Dependency</class>
<class>net.woggioni.jpacrepo.api.model.Packager</class>
<exclude-unlisted-classes>true</exclude-unlisted-classes>
<properties>
<property name="org.jboss.logging.provider" value="log4j2"/>
<property name="jakarta.persistence.schema-generation.database.action"
value="none"/>
<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"/>
@@ -18,7 +24,31 @@
<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.PostgreSQLDialect"/>
</properties>
</persistence-unit>
<!-- <persistence-unit name="squirrel_sql" transaction-type="RESOURCE_LOCAL">-->
<!-- <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>-->
<!-- <class>net.woggioni.jpacrepo.api.model.PkgData</class>-->
<!-- <class>net.woggioni.jpacrepo.api.model.PkgId</class>-->
<!-- <exclude-unlisted-classes>true</exclude-unlisted-classes>-->
<!-- <properties>-->
<!-- <property name="org.jboss.logging.provider" value="log4j2"/>-->
<!-- <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="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.PostgreSQLDialect"/>-->
<!-- <property name="javax.persistence.jdbc.driver" value="org.postgresql.Driver" />-->
<!-- <property name="javax.persistence.jdbc.url" value="jdbc:postgresql:wildfly?readOnly=true" />-->
<!-- <property name="javax.persistence.jdbc.user" value="wildfly" />-->
<!-- <property name="hibernate.jdbc.fetch_size" value="20"/>-->
<!-- <property name="hibernate.default_batch_fetch_size" value="20"/>-->
<!--&lt;!&ndash; <property name="javax.persistence.jdbc.password" value="databasePassword" />&ndash;&gt;-->
<!-- </properties>-->
<!-- </persistence-unit>-->
</persistence>

View File

@@ -12,7 +12,7 @@ import lombok.SneakyThrows;
import net.woggioni.jpacrepo.api.model.PkgData;
import net.woggioni.jpacrepo.api.service.PacmanServiceRemote;
import net.woggioni.jpacrepo.impl.model.CompressionFormatImpl;
import net.woggioni.jpacrepo.impl.model.PkgDataImpl;
import net.woggioni.jpacrepo.impl.model.PkgDataParser;
import net.woggioni.jwo.Con;
import net.woggioni.jwo.Hash;
import net.woggioni.jwo.JWO;
@@ -98,7 +98,7 @@ public class ClientTest {
try(InputStream is = Files.newInputStream(tmpFile)) {
hash = Hash.md5(is);
}
PkgData p = PkgDataImpl.parseFile(tmpFile, CompressionFormatImpl.guess(tmpFile));
PkgData p = PkgDataParser.parseFile(tmpFile, CompressionFormatImpl.guess(tmpFile));
Assertions.assertEquals(JWO.bytesToHex(hash.getBytes()), p.getMd5sum());
});
}
@@ -124,8 +124,8 @@ 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:7080");
// prop.put(Context.PROVIDER_URL, "http-remoting://localhost:8080");
// prop.put(Context.PROVIDER_URL, "http-remoting://localhost:1234");
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");
@@ -138,7 +138,7 @@ 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-2023.07/PacmanServiceEJB!net.woggioni.jpacrepo.api.service.PacmanServiceRemote"
"/jpacrepo/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));

View File

@@ -4,7 +4,7 @@ import com.fasterxml.jackson.module.jakarta.xmlbind.JakartaXmlBindAnnotationModu
import lombok.SneakyThrows;
import net.woggioni.jpacrepo.api.model.PkgData;
import net.woggioni.jpacrepo.impl.model.CompressionFormatImpl;
import net.woggioni.jpacrepo.impl.model.PkgDataImpl;
import net.woggioni.jpacrepo.impl.model.PkgDataParser;
import org.junit.jupiter.api.Test;
import java.lang.reflect.ParameterizedType;
@@ -31,7 +31,7 @@ public class ParseTest {
Files.list(Paths.get("/var/cache/pacman/pkg"))
.filter(Files::isRegularFile)
.filter(p -> pattern.matcher(p.getFileName().toString()).matches())
.map(path -> PkgDataImpl.parseFile(path, CompressionFormatImpl.guess(path)))
.map(path -> PkgDataParser.parseFile(path, CompressionFormatImpl.guess(path)))
.limit(10)
.map(new Function<PkgData, String>() {
@Override