This repository has been archived by the owner on Jul 26, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'main' into feature/customer-api-consumer
- Loading branch information
Showing
19 changed files
with
682 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
64 changes: 64 additions & 0 deletions
64
...-provider/src/main/java/de/schulung/sample/quarkus/infrastructure/LongRunningStartup.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
package de.schulung.sample.quarkus.infrastructure; | ||
|
||
import io.quarkus.runtime.Startup; | ||
import io.smallrye.mutiny.Uni; | ||
import io.smallrye.mutiny.infrastructure.Infrastructure; | ||
import jakarta.enterprise.context.ApplicationScoped; | ||
import jakarta.enterprise.inject.Produces; | ||
import org.eclipse.microprofile.health.HealthCheck; | ||
import org.eclipse.microprofile.health.HealthCheckResponse; | ||
import org.eclipse.microprofile.health.Liveness; | ||
import org.eclipse.microprofile.health.Readiness; | ||
|
||
@ApplicationScoped | ||
public class LongRunningStartup { | ||
|
||
private volatile boolean initialized = false; | ||
private volatile boolean initializingFailed = false; | ||
|
||
// check during startup: http://localhost:9090/q/health/ready | ||
|
||
private Uni<Void> doLongRunningInitialization() { | ||
try { | ||
Thread.sleep(5000); | ||
initialized = true; | ||
return Uni.createFrom().voidItem(); | ||
} catch (InterruptedException e) { | ||
initializingFailed = true; | ||
return Uni.createFrom().failure(e); | ||
} | ||
} | ||
|
||
@Startup | ||
public void init() { | ||
Uni | ||
.createFrom() | ||
.voidItem() | ||
.emitOn(Infrastructure.getDefaultWorkerPool()) | ||
.subscribe() | ||
.with(v -> this.doLongRunningInitialization()); | ||
} | ||
|
||
@Produces | ||
@ApplicationScoped | ||
@Liveness | ||
public HealthCheck myStartupLiveness() { | ||
return () -> { | ||
final var result = HealthCheckResponse | ||
.named("My long-running startup"); | ||
return (initializingFailed ? result.down() : result.up()).build(); | ||
}; | ||
} | ||
|
||
@Produces | ||
@ApplicationScoped | ||
@Readiness | ||
public HealthCheck myStartupReadyness() { | ||
return () -> { | ||
final var result = HealthCheckResponse | ||
.named("My long-running startup"); | ||
return (initialized ? result.up() : result.down()).build(); | ||
}; | ||
} | ||
|
||
} |
31 changes: 31 additions & 0 deletions
31
...mer-api-provider/src/main/java/de/schulung/sample/quarkus/persistence/CustomerEntity.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
package de.schulung.sample.quarkus.persistence; | ||
|
||
import de.schulung.sample.quarkus.domain.Customer; | ||
import jakarta.persistence.*; | ||
import jakarta.validation.constraints.NotNull; | ||
import jakarta.validation.constraints.Size; | ||
import lombok.Getter; | ||
import lombok.Setter; | ||
|
||
import java.time.LocalDate; | ||
import java.util.UUID; | ||
|
||
@Getter | ||
@Setter | ||
@Entity(name = "Customer") | ||
@Table(name = "CUSTOMERS") | ||
public class CustomerEntity { | ||
|
||
@Id | ||
@GeneratedValue(strategy = GenerationType.UUID) | ||
private UUID uuid; | ||
@Size(min = 3, max = 100) | ||
@NotNull | ||
private String name; | ||
@Column(name = "DATE_OF_BIRTH") | ||
private LocalDate birthdate; | ||
@NotNull | ||
//@Enumerated(EnumType.STRING) | ||
private Customer.CustomerState state = Customer.CustomerState.ACTIVE; | ||
|
||
} |
16 changes: 16 additions & 0 deletions
16
...i-provider/src/main/java/de/schulung/sample/quarkus/persistence/CustomerEntityMapper.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
package de.schulung.sample.quarkus.persistence; | ||
|
||
import de.schulung.sample.quarkus.domain.Customer; | ||
import org.mapstruct.Mapper; | ||
import org.mapstruct.MappingTarget; | ||
|
||
@Mapper(componentModel = "cdi") | ||
public interface CustomerEntityMapper { | ||
|
||
CustomerEntity map(Customer source); | ||
|
||
Customer map(CustomerEntity source); | ||
|
||
void copy(CustomerEntity source, @MappingTarget Customer target); | ||
|
||
} |
10 changes: 10 additions & 0 deletions
10
...ovider/src/main/java/de/schulung/sample/quarkus/persistence/CustomerEntityRepository.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
package de.schulung.sample.quarkus.persistence; | ||
|
||
import io.quarkus.hibernate.orm.panache.PanacheRepositoryBase; | ||
import jakarta.enterprise.context.ApplicationScoped; | ||
|
||
import java.util.UUID; | ||
|
||
@ApplicationScoped | ||
public class CustomerEntityRepository implements PanacheRepositoryBase<CustomerEntity, UUID> { | ||
} |
31 changes: 31 additions & 0 deletions
31
...provider/src/main/java/de/schulung/sample/quarkus/persistence/CustomerStateConverter.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
package de.schulung.sample.quarkus.persistence; | ||
|
||
import de.schulung.sample.quarkus.domain.Customer; | ||
import de.schulung.sample.quarkus.domain.Customer.CustomerState; | ||
import jakarta.persistence.AttributeConverter; | ||
import jakarta.persistence.Converter; | ||
import jakarta.persistence.PersistenceException; | ||
|
||
@Converter(autoApply = true) | ||
public class CustomerStateConverter implements AttributeConverter<CustomerState, String> { | ||
|
||
|
||
@Override | ||
public String convertToDatabaseColumn(CustomerState source) { | ||
return null == source ? null : switch (source) { | ||
case ACTIVE -> "a"; | ||
case LOCKED -> "l"; | ||
case DISABLED -> "d"; | ||
}; | ||
} | ||
|
||
@Override | ||
public CustomerState convertToEntityAttribute(String source) { | ||
return null == source ? null : switch (source) { | ||
case "a" -> Customer.CustomerState.ACTIVE; | ||
case "l" -> Customer.CustomerState.LOCKED; | ||
case "d" -> Customer.CustomerState.DISABLED; | ||
default -> throw new PersistenceException(source + " is not allowed here."); | ||
}; | ||
} | ||
} |
207 changes: 207 additions & 0 deletions
207
...-provider/src/main/java/de/schulung/sample/quarkus/persistence/CustomersSinkJdbcImpl.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,207 @@ | ||
package de.schulung.sample.quarkus.persistence; | ||
|
||
import de.schulung.sample.quarkus.domain.Customer; | ||
import de.schulung.sample.quarkus.domain.Customer.CustomerState; | ||
import de.schulung.sample.quarkus.domain.CustomersSink; | ||
import io.quarkus.arc.properties.IfBuildProperty; | ||
import jakarta.enterprise.context.ApplicationScoped; | ||
import jakarta.enterprise.inject.Typed; | ||
import lombok.RequiredArgsConstructor; | ||
|
||
import javax.sql.DataSource; | ||
import java.sql.*; | ||
import java.time.LocalDate; | ||
import java.util.Collection; | ||
import java.util.LinkedList; | ||
import java.util.Optional; | ||
import java.util.UUID; | ||
import java.util.stream.Stream; | ||
|
||
@ApplicationScoped | ||
@Typed(CustomersSink.class) | ||
@RequiredArgsConstructor | ||
@IfBuildProperty( | ||
name = "persistence.sink.implementation", | ||
stringValue = "jdbc" | ||
) | ||
public class CustomersSinkJdbcImpl implements CustomersSink { | ||
|
||
private final DataSource ds; | ||
|
||
/* ******************************************************* * | ||
* Converter methods - could be converter objects instead * | ||
* ******************************************************* */ | ||
|
||
private static UUID convertUuid(String uuid) { | ||
return Optional.ofNullable(uuid) | ||
.map(UUID::fromString) | ||
.orElse(null); | ||
} | ||
|
||
private static String convertUuid(UUID uuid) { | ||
return Optional.ofNullable(uuid) | ||
.map(UUID::toString) | ||
.orElse(null); | ||
} | ||
|
||
private static LocalDate convertDate(Date date) { | ||
return Optional.ofNullable(date) | ||
.map(Date::toLocalDate) | ||
.orElse(null); | ||
} | ||
|
||
private static Date convertDate(LocalDate date) { | ||
return Optional.ofNullable(date) | ||
.map(Date::valueOf) | ||
.orElse(null); | ||
} | ||
|
||
private static CustomerState convertState(int value) { | ||
return CustomerState.values()[value]; | ||
} | ||
|
||
private static int convertState(CustomerState value) { | ||
return Optional.ofNullable(value) | ||
.map(CustomerState::ordinal) | ||
.orElse(0); | ||
|
||
} | ||
|
||
/* ******************************************************* * | ||
* Row Mapping - could be a RowMapper object instead * | ||
* ******************************************************* */ | ||
|
||
private static Customer readSingle(ResultSet rs) throws SQLException { | ||
return Customer.builder() | ||
.uuid(convertUuid(rs.getString("UUID"))) | ||
.birthdate(convertDate(rs.getDate("DATE_OF_BIRTH"))) | ||
.name(rs.getString("NAME")) | ||
.state(convertState(rs.getInt("STATE"))) | ||
.build(); | ||
} | ||
|
||
private static Stream<Customer> readAll(ResultSet rs) throws SQLException { | ||
Collection<Customer> result = new LinkedList<>(); | ||
while (rs.next()) { | ||
result.add(readSingle(rs)); | ||
} | ||
return result.stream(); | ||
} | ||
|
||
/* ******************************************************* * | ||
* CustomersSink implementation * | ||
* ******************************************************* */ | ||
|
||
@Override | ||
public Stream<Customer> findAll() { | ||
try (Connection con = ds.getConnection(); | ||
Statement stmt = con.createStatement(); | ||
ResultSet rs = stmt.executeQuery( | ||
"select * from CUSTOMERS" | ||
)) { | ||
|
||
return readAll(rs); | ||
|
||
} catch (SQLException e) { | ||
throw new RuntimeException(e); // eigene Exception? | ||
} | ||
} | ||
|
||
@Override | ||
public Stream<Customer> findByState(CustomerState state) { | ||
try (Connection con = ds.getConnection(); | ||
PreparedStatement stmt = con.prepareStatement( | ||
"select * from CUSTOMERS where STATE=?" | ||
)) { | ||
|
||
stmt.setInt(1, convertState(state)); | ||
|
||
try (ResultSet rs = stmt.executeQuery()) { | ||
return readAll(rs); | ||
} | ||
|
||
} catch (SQLException e) { | ||
throw new RuntimeException(e); // eigene Exception? | ||
} | ||
} | ||
|
||
@Override | ||
public Optional<Customer> findByUuid(UUID uuid) { | ||
try (Connection con = ds.getConnection(); | ||
PreparedStatement stmt = con.prepareStatement( | ||
"select * from CUSTOMERS where UUID=?" | ||
)) { | ||
|
||
stmt.setString(1, convertUuid(uuid)); | ||
|
||
try (ResultSet rs = stmt.executeQuery()) { | ||
if (!rs.next()) { | ||
return Optional.empty(); | ||
} | ||
return Optional.of(readSingle(rs)); | ||
} | ||
|
||
} catch (SQLException e) { | ||
throw new RuntimeException(e); // eigene Exception? | ||
} | ||
} | ||
|
||
@Override | ||
public void save(Customer customer) { | ||
// TODO only insert, we need an update too, if the UUID is already set | ||
try (Connection con = ds.getConnection(); | ||
PreparedStatement stmt = con.prepareStatement( | ||
"insert into CUSTOMERS(NAME,DATE_OF_BIRTH,STATE) values(?,?,?)", | ||
Statement.RETURN_GENERATED_KEYS | ||
)) { | ||
|
||
stmt.setString(1, customer.getName()); | ||
stmt.setDate(2, convertDate(customer.getBirthdate())); | ||
stmt.setInt(3, convertState(customer.getState())); | ||
stmt.executeUpdate(); | ||
|
||
try (ResultSet rs = stmt.getGeneratedKeys()) { | ||
if (!rs.next()) { | ||
throw new RuntimeException("not expected"); // bessere Exception | ||
} | ||
customer.setUuid(convertUuid(rs.getString(1))); | ||
} | ||
|
||
} catch (SQLException e) { | ||
throw new RuntimeException(e); // eigene Exception? | ||
} | ||
} | ||
|
||
@Override | ||
public boolean delete(UUID uuid) { | ||
try (Connection con = ds.getConnection(); | ||
PreparedStatement stmt = con.prepareStatement( | ||
"delete from CUSTOMERS where UUID=?" | ||
)) { | ||
|
||
stmt.setString(1, convertUuid(uuid)); | ||
return stmt.executeUpdate() > 0; | ||
|
||
} catch (SQLException e) { | ||
throw new RuntimeException(e); // eigene Exception? | ||
} | ||
} | ||
|
||
@Override | ||
public long count() { | ||
try (Connection con = ds.getConnection(); | ||
Statement stmt = con.createStatement(); | ||
ResultSet rs = stmt.executeQuery( | ||
"select count(uuid) from CUSTOMERS" | ||
)) { | ||
|
||
if (!rs.next()) { | ||
return 0; | ||
} | ||
return rs.getLong(1); | ||
|
||
} catch (SQLException e) { | ||
throw new RuntimeException(e); // eigene Exception? | ||
} | ||
} | ||
} |
Oops, something went wrong.