backend migrated to Java 17
This commit is contained in:
@@ -14,4 +14,5 @@ open module net.woggioni.jpacrepo {
|
||||
requires org.slf4j;
|
||||
|
||||
requires net.woggioni.jpacrepo.api;
|
||||
requires org.apache.commons.compress;
|
||||
}
|
@@ -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
|
||||
|
@@ -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);
|
||||
}
|
||||
}
|
||||
|
@@ -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;
|
||||
|
@@ -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);
|
||||
}
|
||||
}
|
@@ -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
|
||||
|
281
src/main/java/net/woggioni/jpacrepo/service/jpa/Queries.java
Normal file
281
src/main/java/net/woggioni/jpacrepo/service/jpa/Queries.java
Normal 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);
|
||||
}
|
||||
|
||||
}
|
@@ -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);
|
||||
}
|
||||
}
|
@@ -1,31 +0,0 @@
|
||||
package net.woggioni.jpacrepo.service.wire;
|
||||
|
||||
|
||||
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.List;
|
||||
|
||||
@XmlRootElement
|
||||
public class PkgDataList extends ArrayList<PkgData> {
|
||||
|
||||
public PkgDataList(List<PkgData> l) {
|
||||
for (PkgData el : l) add(el);
|
||||
}
|
||||
|
||||
public PkgDataList(PkgData... elements) {
|
||||
for (PkgData el : elements) add(el);
|
||||
}
|
||||
|
||||
@XmlElement(name = "pkgData")
|
||||
List<PkgData> getItems() {
|
||||
return this;
|
||||
}
|
||||
|
||||
void setItems(List<PkgData> pkgs) {
|
||||
this.clear();
|
||||
this.addAll(pkgs);
|
||||
}
|
||||
}
|
@@ -1,14 +0,0 @@
|
||||
package net.woggioni.jpacrepo.service.wire;
|
||||
|
||||
import jakarta.xml.bind.annotation.XmlRootElement;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
@XmlRootElement
|
||||
public class PkgTuple {
|
||||
String md5sum;
|
||||
|
||||
String filename;
|
||||
|
||||
long size;
|
||||
}
|
@@ -1,29 +0,0 @@
|
||||
package net.woggioni.jpacrepo.service.wire;
|
||||
|
||||
import jakarta.xml.bind.annotation.XmlElement;
|
||||
import jakarta.xml.bind.annotation.XmlRootElement;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@XmlRootElement
|
||||
public class StringList extends ArrayList<String> {
|
||||
|
||||
public StringList(Iterable<String> l) {
|
||||
for (String el : l) add(el);
|
||||
}
|
||||
|
||||
public StringList(String... strings) {
|
||||
for (String el : strings) add(el);
|
||||
}
|
||||
|
||||
@XmlElement(name = "pkgData")
|
||||
List<String> getItems() {
|
||||
return this;
|
||||
}
|
||||
|
||||
void setItems(List<String> strings) {
|
||||
this.clear();
|
||||
this.addAll(strings);
|
||||
}
|
||||
}
|
@@ -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>
|
@@ -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>
|
||||
|
@@ -12,7 +12,7 @@
|
||||
|
||||
<error-page>
|
||||
<error-code>404</error-code>
|
||||
<location>404.xhtml</location>
|
||||
<location>/404.xhtml</location>
|
||||
</error-page>
|
||||
|
||||
</web-app>
|
||||
|
@@ -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());
|
||||
}
|
||||
|
||||
}
|
34
src/test/java/EJBTest.java
Normal file
34
src/test/java/EJBTest.java
Normal 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();
|
||||
}
|
||||
|
||||
}
|
Reference in New Issue
Block a user