Skip to content
Snippets Groups Projects
Commit 51b20698 authored by Tomáš Holub's avatar Tomáš Holub
Browse files

#1 - Nahrání quarkus projektu

oprava bidirectional grpc, migration, sequence import, Sequence model, repository
parent 73477dca
Branches
1 merge request!3#1 - Nahrání quarkus projektu
Pipeline #148616 failed with stage
in 18 seconds
Showing
with 555 additions and 90 deletions
...@@ -22,7 +22,16 @@ dependencies { ...@@ -22,7 +22,16 @@ dependencies {
implementation 'io.quarkus:quarkus-jdbc-postgresql' implementation 'io.quarkus:quarkus-jdbc-postgresql'
implementation 'io.quarkus:quarkus-arc' implementation 'io.quarkus:quarkus-arc'
implementation 'io.quarkus:quarkus-resteasy-reactive' implementation 'io.quarkus:quarkus-resteasy-reactive'
implementation 'io.quarkus:quarkus-hibernate-orm-panache'
implementation 'io.quarkus:quarkus-config-yaml'
implementation 'commons-io:commons-io:2.+'
testImplementation 'io.quarkus:quarkus-junit5' testImplementation 'io.quarkus:quarkus-junit5'
compileOnly group: 'org.projectlombok', name: 'lombok', version: '1.18.26'
annotationProcessor group: 'org.projectlombok', name: 'lombok', version: '1.18.26'
annotationProcessor("io.quarkus:quarkus-panache-common")
} }
group 'cz.mendelu' group 'cz.mendelu'
......
...@@ -2,39 +2,23 @@ version: '3.8' ...@@ -2,39 +2,23 @@ version: '3.8'
services: services:
sequence_postgres: sequence_postgres:
image: postgres:13-alpine image: postgres:12
environment: environment:
- POSTGRES_USER=postgres POSTGRES_DB: sequence_postgres
- POSTGRES_PASSWORD=postgres POSTGRES_USER: ${POSTGRES_USER:-developer}
- POSTGRES_DB=sequence_postgres POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-password}
ports: PGDATA: /data/sequence_postgres
- 5432:5432
sequence_pgadmin:
image: dpage/pgadmin4:latest
depends_on:
- sequence_postgres
environment:
PGADMIN_DEFAULT_EMAIL: ${PGADMIN_DEFAULT_EMAIL:-user@mendelu.cz}
PGADMIN_DEFAULT_PASSWORD: ${PGADMIN_DEFAULT_PASSWORD:-user}
volumes: volumes:
- sequence_pgadmin:/root/.sequence_pgadmin - sequence_postgres:/data/sequence_postgres
ports: ports:
- 5051:80 - 5433:5432
sequence_adminer:
image: adminer
depends_on:
- sequence_postgres
environment:
ADMINER_DEFAULT_SERVER: sequence_postgres
ports:
- 5001:8080
dnaanalyser_backend: dnaanalyser_backend:
image: dnaanalyser/dna-analyser:${TAG:-latest} image: dnaanalyser/dna-analyser:${TAG:-latest}
depends_on: depends_on:
- backend_postgres - backend_postgres
environment:
- SPRING_PROFILES_ACTIVE=dev
volumes: volumes:
- backend_db:/home/app/db - backend_db:/home/app/db
- backend_logs:/home/app/logs - backend_logs:/home/app/logs
...@@ -43,7 +27,7 @@ services: ...@@ -43,7 +27,7 @@ services:
- 50051:50051 - 50051:50051
backend_postgres: backend_postgres:
image: postgres:13 image: postgres:12
environment: environment:
POSTGRES_DB: dna_analyser POSTGRES_DB: dna_analyser
POSTGRES_USER: ${POSTGRES_USER:-developer} POSTGRES_USER: ${POSTGRES_USER:-developer}
...@@ -51,11 +35,14 @@ services: ...@@ -51,11 +35,14 @@ services:
PGDATA: /data/backend_postgres PGDATA: /data/backend_postgres
volumes: volumes:
- backend_postgres:/data/backend_postgres - backend_postgres:/data/backend_postgres
ports:
- 5432:5432
backend_pgadmin: pgadmin:
image: dpage/pgadmin4:latest image: dpage/pgadmin4:latest
depends_on: depends_on:
- backend_postgres - backend_postgres
- sequence_postgres
environment: environment:
PGADMIN_DEFAULT_EMAIL: ${PGADMIN_DEFAULT_EMAIL:-user@mendelu.cz} PGADMIN_DEFAULT_EMAIL: ${PGADMIN_DEFAULT_EMAIL:-user@mendelu.cz}
PGADMIN_DEFAULT_PASSWORD: ${PGADMIN_DEFAULT_PASSWORD:-user} PGADMIN_DEFAULT_PASSWORD: ${PGADMIN_DEFAULT_PASSWORD:-user}
...@@ -64,10 +51,11 @@ services: ...@@ -64,10 +51,11 @@ services:
ports: ports:
- 5050:80 - 5050:80
backend_adminer: adminer:
image: adminer image: adminer
depends_on: depends_on:
- backend_postgres - backend_postgres
- sequence_postgres
environment: environment:
ADMINER_DEFAULT_SERVER: backend_postgres ADMINER_DEFAULT_SERVER: backend_postgres
ports: ports:
......
...@@ -87,9 +87,7 @@ COPY --chown=185 build/quarkus-app/app/ /deployments/app/ ...@@ -87,9 +87,7 @@ COPY --chown=185 build/quarkus-app/app/ /deployments/app/
COPY --chown=185 build/quarkus-app/quarkus/ /deployments/quarkus/ COPY --chown=185 build/quarkus-app/quarkus/ /deployments/quarkus/
EXPOSE 8080 EXPOSE 8080
EXPOSE 5005
USER 185 USER 185
ENV JAVA_OPTS="-Dquarkus.http.host=0.0.0.0 -Djava.util.logging.manager=org.jboss.logmanager.LogManager" ENV JAVA_OPTS="-Dquarkus.http.host=0.0.0.0 -Djava.util.logging.manager=org.jboss.logmanager.LogManager -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005"
ENV JAVA_APP_JAR="/deployments/quarkus-run.jar" ENV JAVA_APP_JAR="/deployments/quarkus-run.jar"
# live coding
#ENV QUARKUS_LAUNCH_DEVMODE=true
package cz.mendelu;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
/**
* Example JPA entity.
*
* To use it, get access to a JPA EntityManager via injection.
*
* {@code
* @Inject
* EntityManager em;
*
* public void doSomething() {
* MyEntity entity1 = new MyEntity();
* entity1.field = "field-1";
* em.persist(entity1);
*
* List<MyEntity> entities = em.createQuery("from MyEntity", MyEntity.class).getResultList();
* }
* }
*/
@Entity
public class MyEntity {
@Id
@GeneratedValue
public Long id;
public String field;
}
package cz.mendelu.grpc.client; package cz.mendelu.api.grpcclient;
import grpc.sequence.GreeterGrpc; import grpc.sequence.GreeterGrpc;
import grpc.sequence.Hello; import grpc.sequence.Hello;
......
package cz.mendelu.grpc.client; package cz.mendelu.api.grpcclient;
import javax.inject.Inject; import javax.inject.Inject;
import javax.ws.rs.GET; import javax.ws.rs.GET;
...@@ -11,10 +11,14 @@ public class HelloGrpcTestController { ...@@ -11,10 +11,14 @@ public class HelloGrpcTestController {
@Inject @Inject
HelloGrpcClientTest helloGrpcClientTest; HelloGrpcClientTest helloGrpcClientTest;
@Inject
SomeTransactionTest someTransactionTest;
@GET @GET
@Produces(MediaType.TEXT_PLAIN) @Produces(MediaType.TEXT_PLAIN)
public String hello() { public String hello() {
someTransactionTest.persistSequence();
return "helloRR"; return "helloRR";
} }
......
package cz.mendelu.api.grpcclient;
import cz.mendelu.model.Sequence;
import javax.enterprise.context.ApplicationScoped;
import javax.transaction.Transactional;
import java.util.UUID;
@ApplicationScoped
public class SomeTransactionTest {
@Transactional
public void persistSequence() {
String str = "987acc67-5714-47b1-b56f-1dc56ded7c87";
UUID uuid = UUID.fromString(str);
Sequence sequence = Sequence.findById(uuid);
sequence.circular = false;
sequence.persist();
}
}
package cz.mendelu.grpc.server; package cz.mendelu.api.grpcserver;
import grpc.sequence.GreeterGrpc; import grpc.sequence.GreeterGrpc;
import grpc.sequence.Hello; import grpc.sequence.Hello;
...@@ -11,7 +11,7 @@ public class HelloGrpcService extends GreeterGrpc.GreeterImplBase { ...@@ -11,7 +11,7 @@ public class HelloGrpcService extends GreeterGrpc.GreeterImplBase {
@Override @Override
public void sayHello(Hello.HelloRequest request, StreamObserver<Hello.HelloReply> responseObserver) { public void sayHello(Hello.HelloRequest request, StreamObserver<Hello.HelloReply> responseObserver) {
String name = request.getName(); String name = request.getName();
String message = "Hello " + name; String message = "Helklgo " + name;
responseObserver.onNext(Hello.HelloReply.newBuilder().setMessage(message).build()); responseObserver.onNext(Hello.HelloReply.newBuilder().setMessage(message).build());
responseObserver.onCompleted(); responseObserver.onCompleted();
} }
......
package cz.mendelu.model;
/**
* Created by Jan Kolomazník on 27.6.17.
*/
public enum Nucleotide {
A('A', 'T', 'U'),
B('B'),
C('C', 'G', 'G'),
D('D'),
G('G', 'C', 'C'),
H('H'),
K('K'),
M('M'),
N('N'),
R('R'),
S('S'),
T('T', 'A'),
U('U', Nucleotide.ASCIINULL, 'A'),
V('V'),
W('W'),
Y('Y'),
NONE();
static final private char ASCIINULL = (char) 0;
private final byte rawByte;//internal raw representation
private final byte dnaSupplement;
private final byte rnaSupplement;
Nucleotide() {
this(ASCIINULL);
}
Nucleotide(char raw) {
this(raw, ASCIINULL);
}
Nucleotide(char raw, char dSupplement) {
this(raw, dSupplement, ASCIINULL);
}
Nucleotide(char raw, char dSupplement, char rSupplement) {
this.rawByte = (byte) raw;
this.dnaSupplement = (byte) dSupplement;
this.rnaSupplement = (byte) rSupplement;
}
/**
* slower but safer way to transform ascii char from source that was not converted to internal format
*
* @param b ascii letter converted to byte
* @return nucleic base
*/
// TODO(T. Holub) resolve dependencies
/*
public static Nucleotide get(byte b) {
return getFromInternalFormat(RawDataProcessor.toInternal(b));
}
*/
/**
* Faster way to get nucleic from internal format string
*
* @param b byte of internal format data
* @return nucleic base
*/
public static Nucleotide getFromInternalFormat(byte b) {
switch (b) {
case 65:
return A;
case 66:
return B;
case 67:
return C;
case 68:
return D;
case 71:
return G;
case 72:
return H;
case 75:
return K;
case 77:
return M;
case 78:
return N;
case 82:
return R;
case 83:
return S;
case 84:
return T;
case 85:
return U;
case 86:
return V;
case 87:
return W;
case 89:
return Y;
default:
return NONE;
}
}
//save way for getting nucleic from general java char
public static Nucleotide get(char b) {
switch (Character.toUpperCase(b)) {
case 'A':
return A;
case 'B':
return B;
case 'C':
return C;
case 'D':
return D;
case 'G':
return G;
case 'H':
return H;
case 'K':
return K;
case 'M':
return M;
case 'N':
return N;
case 'R':
return R;
case 'S':
return S;
case 'T':
return T;
case 'U':
return U;
case 'V':
return V;
case 'W':
return W;
case 'Y':
return Y;
default:
return NONE;
}
}
public boolean isSupplement(Nucleotide nucleotide, SequenceType type) {
return (type == SequenceType.DNA)
? this.dnaSupplement == nucleotide.rawByte
: this.rnaSupplement == nucleotide.rawByte;
}
public Nucleotide supplement(SequenceType type) {
return (type == SequenceType.DNA)
? getFromInternalFormat(dnaSupplement)
: getFromInternalFormat(rnaSupplement);
}
public byte toByte() {
return rawByte;
}
/**
* return true if it is not convertible to nucleic
*
* @param in ascii letter from internal format string
* @return true or false
*/
public static boolean isNuclidInInernal(byte in) {
switch (in) {
case 65:
case 66:
case 67:
case 68:
case 71:
case 72:
case 75:
case 77:
case 78:
case 82:
case 83:
case 84:
case 85:
case 86:
case 87:
case 89:
return true;
default:
return false;
}
}
}
package cz.mendelu.model;
import com.fasterxml.jackson.annotation.JsonIgnore;
import io.quarkus.runtime.annotations.RegisterForReflection;
import org.hibernate.annotations.CreationTimestamp;
import javax.persistence.*;
import java.util.*;
import java.util.stream.Collectors;
@Entity
@Table(name = "sequences")
public class Sequence extends UUIDPanacheEntity {
@JsonIgnore
@Column(name = "buffer_id")
public UUID bufferId;
public String name;
@Temporal(TemporalType.TIMESTAMP)
@CreationTimestamp
public Date created;
public SequenceType type;
public Boolean circular;
public Integer length;
public String ncbi;
@ElementCollection
public Set<String> tags;
@Column(name = "owner_id")
@JsonIgnore
public UUID ownerId;
@Column(name = "fasta_comment")
public String fastaComment;
@ElementCollection
@CollectionTable(name = "sequence_nucleic_counts")
@MapKeyColumn(name = "nucleic_counts_key")
@Column(name = "nucleic_counts")
public Map<Nucleotide, Integer> nucleicCounts;
public Map<Nucleotide, Integer> getNucleicCounts() {
return (nucleicCounts == null || nucleicCounts.isEmpty())
? null
: Collections.unmodifiableMap(nucleicCounts);
}
public static List<Sequence> findAllByOwnerIsNull() {
return list("ownerId IS NULL");
}
public static Optional<String> getNcbi(UUID id) {
Optional<Sequence> sequence = findByIdOptional(id);
return sequence.map(s -> s.ncbi);
}
public static Optional<String> getName(UUID id) {
Optional<Sequence> sequence = findByIdOptional(id);
return sequence.map(s -> s.name);
}
public static List<Sequence> findAll(UUID ownerId) {
return list("ownerId = ?1", ownerId);
}
public static List<Sequence> findAll(UUID ownerId, String tag) {
return list("ownerId = ?1 and ?2 member of tags", ownerId, tag);
}
public static Optional<Sequence> findById(UUID id, UUID ownerId) {
return find("id = ?1 and ownerId = ?2", id, ownerId)
.firstResultOptional();
}
public static List<String> findAllTags(UUID ownerId) {
List<TagRecord> tagRecords = Sequence.find("SELECT DISTINCT t FROM Sequence s, IN (s.tags) t WHERE s.ownerId = ?1", ownerId)
.project(TagRecord.class)
.list();
return tagRecords.stream()
.map(TagRecord::tag)
.collect(Collectors.toList());
}
public static List<Sequence> findByNcbi(String ncbi) {
return list("ncbi", ncbi);
}
@RegisterForReflection
public record TagRecord(String tag) {
}
}
package cz.mendelu.model;
public enum SequenceType {
DNA, RNA
}
package cz.mendelu.model;
import com.google.common.base.MoreObjects;
import com.google.common.base.Objects;
import io.quarkus.hibernate.orm.panache.PanacheEntityBase;
import javax.persistence.Id;
import javax.persistence.MappedSuperclass;
import java.util.UUID;
@MappedSuperclass
public class UUIDPanacheEntity extends PanacheEntityBase {
@Id
public UUID id = UUID.randomUUID();
@Override
public String toString() {
return MoreObjects.toStringHelper(this)
.add("id", id)
.toString();
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
UUIDPanacheEntity that = (UUIDPanacheEntity) o;
return Objects.equal(id, that.id);
}
@Override
public int hashCode() {
return Objects.hashCode(id);
}
}
package cz.mendelu.repository;
public interface SequenceRepository {
/*
List<Sequence> findAllByOwnerIsNull();
@Query("SELECT ncbi FROM Sequence WHERE id=:id")
String getNcbi(@Param("id") UUID id);
@Query("SELECT name FROM Sequence WHERE id=:id")
String getName(@Param("id") UUID id);
@Query("select s from Sequence as s join s.owner o where o.id = ?#{principal.id}")
Page<Sequence> findAll(Pageable pageable);
@Query("select s from Sequence as s join s.owner o join s.tags t where t = :tag and o.id = ?#{principal.id}")
Page<Sequence> findAll(Pageable pageable, @Param("tag") String tag);
@Query("select s from Sequence as s join s.owner o where s.id = :id and o.id = ?#{principal.id}")
Optional<Sequence> findById(@Param("id") UUID id);
@Query("select distinct t from Sequence as s join s.owner o join s.tags t where o.id = ?#{principal.id}")
Page<String> findAllTags(Pageable pageable);
List<Sequence> findByNcbi(String ncbi);
*/
}
package cz.mendelu.util.exception;
public class ImporterException extends RuntimeException {
public ImporterException(String message, Throwable cause) {
super(message, cause);
}
}
package cz.mendelu.util.importer;
import cz.mendelu.util.exception.ImporterException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import javax.enterprise.context.ApplicationScoped;
import java.io.*;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import static java.text.MessageFormat.format;
@ApplicationScoped
@Slf4j
public class FirstRunImporter {
public void importFiles(String srcResourceDir, String destDir) {
log.debug("Import files from {} to {}.", srcResourceDir, destDir);
Path destPath = Paths.get(destDir);
prepareDestDir(destPath);
List<File> resources = findResourcesByMatchingPattern(new File(srcResourceDir));
resources.forEach(r -> copyFile(r, destPath));
}
private void prepareDestDir(Path destPath) {
try {
if (Files.notExists(destPath)) {
Files.createDirectories(destPath);
log.debug("Create destination directory {}.", destPath);
}
} catch (IOException e) {
throw new ImporterException(format("Can't create directory {}.", destPath), e);
}
}
private List<File> findResourcesByMatchingPattern(File srcDir) {
List<File> files = new ArrayList<>();
File[] matchedFiles = srcDir.listFiles();
if (matchedFiles != null) {
files.addAll(Arrays.asList(matchedFiles));
log.debug("Found {} resources to import from {}", files.size(), srcDir);
}
return files;
}
private void copyFile(File file, Path destPath) {
try (InputStream in = new FileInputStream(file)) {
if (in == null) {
log.error("InputStream from file {} is null.", file);
return;
}
Path target = destPath.resolve(file.getName());
if (Files.exists(target)) {
log.debug("Skip copy file from {} to {}.", file, destPath);
return;
}
try (OutputStream out = new FileOutputStream(target.toFile())) {
IOUtils.copyLarge(in, out);
log.info("Extract file {} to {}", file, destPath);
}
} catch (Exception e) {
log.warn("Create default file failed.", e);
}
}
}
package cz.mendelu.util.importer;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.microprofile.config.inject.ConfigProperty;
import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.context.Initialized;
import javax.enterprise.event.Observes;
import javax.inject.Inject;
@ApplicationScoped
@Slf4j
public class SequenceImporter {
@Inject
FirstRunImporter importer;
@ConfigProperty(name = "sequence.dir")
String destDir;
void onStart(@Observes @Initialized(ApplicationScoped.class) Object ev) {
copyDefaultSequencesToWorkingDirectory();
}
public void copyDefaultSequencesToWorkingDirectory() {
try {
importer.importFiles("db/data/sequences/", destDir);
log.info("Created default sequences.");
} catch (Exception e) {
log.warn("Create default sequences failed.", e);
}
}
}
package cz.mendelu.util.model;
import java.util.UUID;
public interface Identifiable {
UUID getId();
}
package cz.mendelu.util.model;
import java.util.Set;
public interface Tagged {
void setTags(Set<String> tags);
Set<String> getTags();
}
...@@ -11,5 +11,5 @@ message HelloReply { ...@@ -11,5 +11,5 @@ message HelloReply {
} }
service Greeter { service Greeter {
rpc sayHello (HelloRequest) returns (HelloReply); rpc sayHello (HelloRequest) returns (HelloReply) {};
} }
# GLOBAL
# -----------
quarkus.hibernate-orm.database.generation=drop-and-create
quarkus.datasource.devservices.enabled=false
quarkus.datasource.db-kind=pg
quarkus.datasource.username=postgres
quarkus.datasource.password=postgres
quarkus.datasource.jdbc.url=jdbc:postgresql://sequence_postgres:5432/sequence_postgres
quarkus.datasource.jdbc.max-size=16
%prod.quarkus.datasource.username=postgres
%prod.quarkus.datasource.password=postgres
quarkus.grpc.server.port=50052
quarkus.grpc.server.enable-reflection-service=true
quarkus.grpc.clients.greeter.host=localhost
quarkus.grpc.clients.greeter.port=50051
quarkus.grpc.clients.greeter.plain-text=true
quarkus.grpc.clients.greeter.keep-alive-without-calls=true
quarkus.grpc.clients.greeter.negotiation-type=PLAINTEXT
# DEV
# -----------
%dev.quarkus.datasource.jdbc.url=jdbc:postgresql://host.docker.internal:5432/sequence_postgres
\ No newline at end of file
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment