Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 9 additions & 13 deletions cloudbank-v4/customer-helidon/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,39 +1,35 @@

# 1st stage, build the app
FROM container-registry.oracle.com/java/jdk-no-fee-term:21 as build

# Install maven
WORKDIR /usr/share
RUN set -x && \
curl -O https://archive.apache.org/dist/maven/maven-3/3.8.4/binaries/apache-maven-3.8.4-bin.tar.gz && \
tar -xvf apache-maven-*-bin.tar.gz && \
tar -xvf apache-maven-*-bin.tar.gz && \
rm apache-maven-*-bin.tar.gz && \
mv apache-maven-* maven && \
ln -s /usr/share/maven/bin/mvn /bin/

WORKDIR /helidon

# Create a first layer to cache the "Maven World" in the local repository.
# Incremental docker builds will always resume after that, unless you update
# the pom
ADD pom.xml .
RUN mvn package -Dmaven.test.skip -Declipselink.weave.skip -Declipselink.weave.skip -DskipOpenApiGenerate
RUN mvn package -Dmaven.test.skip -Declipselink.weave.skip -DskipOpenApiGenerate

# Do the Maven build!
# Incremental docker builds will resume here when you change sources
# Do the Maven build with fat JAR!
ADD src src
RUN mvn package -DskipTests

RUN echo "done!"

# 2nd stage, build the runtime image
FROM container-registry.oracle.com/java/jdk-no-fee-term:21

WORKDIR /helidon

# Copy the binary built in the 1st stage
COPY --from=build /helidon/target/customer-helidon.jar ./
COPY --from=build /helidon/target/libs ./libs
# Copy ONLY the fat JAR (not libs directory)
COPY --from=build /helidon/target/*.jar app.jar

CMD ["java", "-jar", "customer-helidon.jar"]
# Simple fat JAR execution
CMD ["java", "-jar", "app.jar"]

EXPOSE 8080

204 changes: 163 additions & 41 deletions cloudbank-v4/customer-helidon/README.md
Original file line number Diff line number Diff line change
@@ -1,27 +1,80 @@
# customer-helidon

Helidon MP version of the "customer" microservice.
Helidon MP version of the "customer" microservice built using the **Helidon MP profile** for enterprise Java applications with CDI, JPA, and microservices capabilities.

## Build and run

### Prerequisites
- JDK 21
- Maven 3.8+

### Building the Application

The build process creates a **thin JAR deployment package** as a ZIP file containing the application JAR and all dependencies:

With JDK21
```bash
mvn package
java -jar target/customer-helidon.jar
mvn clean package
```

## Exercise the application
This creates:
- `target/customer-helidon.jar` - The thin application JAR
- `target/customer-helidon-deployment.zip` - Complete deployment package with structure:
```
customer-helidon.jar (main application)
app/
libs/ (all dependency JARs)
```

### Running the Application

Basic:
**Option 1: Using the thin JAR (requires dependencies in classpath):**
```bash
# Extract the deployment ZIP first
cd target
unzip customer-helidon-deployment.zip
java -jar customer-helidon.jar
```
curl -X GET http://localhost:8080/simple-greet
Hello World!

**Option 2: Using Maven to run directly:**
```bash
mvn exec:java
```

## Quick Start with Local Oracle Database

To run against a local Oracle Docker container, simply:

JSON:
1. **Start Oracle Database container:**
```bash
docker run -d --name oracle-db -p 1521:1521 \
-e ORACLE_PWD=Welcome12345 \
container-registry.oracle.com/database/free:latest
```

2. **Uncomment database configuration** in `src/main/resources/application.yaml`:
```yaml
javax.sql.DataSource.customer.URL = jdbc:oracle:thin:@//localhost:1521/freepdb1
javax.sql.DataSource.customer.user = customer
javax.sql.DataSource.customer.password = Welcome12345
```

3. **Rebuild and run:**
```bash
mvn clean package
cd target && unzip customer-helidon-deployment.zip
java -jar customer-helidon.jar
```

The application will automatically create the necessary database tables on startup using Hibernate's DDL auto-generation.

### Basic:
```bash
curl -X GET http://localhost:8080/simple-greet
Hello World!
```

### JSON:
```bash
curl -X GET http://localhost:8080/greet
{"message":"Hello World!"}

Expand All @@ -34,61 +87,130 @@ curl -X GET http://localhost:8080/greet/Jose
{"message":"Hola Jose!"}
```



## Try health

```
### Try health
```bash
curl -s -X GET http://localhost:8080/health
{"outcome":"UP",...

```

### Try metrics
```bash
# Prometheus Format
curl -s -X GET http://localhost:8080/metrics
# TYPE base:gc_g1_young_generation_count gauge
. . .

# JSON Format
curl -H 'Accept: application/json' -X GET http://localhost:8080/metrics
{"base":...
. . .
```

## Building a Native Image

The generation of native binaries requires an installation of GraalVM 22.1.0+.

You can build a native binary using Maven as follows:

```
```bash
mvn -Pnative-image install -DskipTests
```

The generation of the executable binary may take a few minutes to complete depending on
your hardware and operating system. When completed, the executable file will be available
under the `target` directory and be named after the artifact ID you have chosen during the
project generation phase.

The generation of the executable binary may take a few minutes to complete depending on your hardware and operating system. When completed, the executable file will be available under the `target` directory and be named after the artifact ID you have chosen during the project generation phase.

## Docker Support

## Try metrics
### Building the Docker Image
```bash
docker build -t customer-helidon .
```

### Running the Docker Image
```bash
docker run --rm -p 8080:8080 customer-helidon:latest
```
# Prometheus Format
curl -s -X GET http://localhost:8080/metrics
# TYPE base:gc_g1_young_generation_count gauge
. . .

# JSON Format
curl -H 'Accept: application/json' -X GET http://localhost:8080/metrics
{"base":...
. . .
Exercise the application as described above.

## Configuration

### Application Properties (`application.yaml`)
```yaml
# Microprofile server properties
server.port=8080
server.host=0.0.0.0
# Change the following to true to enable the optional MicroProfile Metrics REST.request metrics
metrics.rest-request.enabled=false

# Application properties. This is the default greeting
app.greeting=Hello

# Database connection factory - specifies Oracle UCP driver for connection pooling
javax.sql.DataSource.customer.connectionFactoryClassName = oracle.jdbc.pool.OracleDataSource

# Local Oracle Database Configuration
# Uncomment the following lines to connect to a local Oracle Docker container out-of-the-box:
# javax.sql.DataSource.customer.URL = jdbc:oracle:thin:@//localhost:1521/freepdb1
# javax.sql.DataSource.customer.user = customer
# javax.sql.DataSource.customer.password = Welcome12345

# Hibernate/JPA Configuration
hibernate.hbm2ddl.auto=create
hibernate.show_sql=true
hibernate.format_sql=true
# Fix JTA transaction coordinator issue
hibernate.transaction.coordinator_class=jta

# Eureka service discovery configuration
server.features.eureka.client.base-uri=http://eureka.eureka:8761/eureka
server.features.eureka.instance.name=helidon-customer-service
server.features.eureka.instance.hostName=helidon.helidon
```

## Build Architecture

This project uses:
- **Helidon MP (MicroProfile)** - Enterprise Java microservices profile
- **Thin JAR deployment** - Application JAR + separate dependencies for optimal Docker layering
- **Maven Assembly Plugin** - Creates deployment ZIP with proper structure for containerization
- **Hibernate + JTA** - Database persistence with transaction management
- **Oracle UCP** - Connection pooling for Oracle Database
- **Eureka integration** - Service discovery support

## Building the Docker Image
## Dockerfile Structure

```
docker build -t customer-helidon .
```
The included Dockerfile uses a **multi-stage build**:

## Running the Docker Image
```dockerfile
# 1st stage, build the app
FROM container-registry.oracle.com/java/jdk-no-fee-term:21 as build

```
docker run --rm -p 8080:8080 customer-helidon:latest
```
# Install maven
WORKDIR /usr/share
RUN set -x && \
curl -O https://archive.apache.org/dist/maven/maven-3/3.8.4/binaries/apache-maven-3.8.4-bin.tar.gz && \
tar -xvf apache-maven-*-bin.tar.gz && \
rm apache-maven-*-bin.tar.gz && \
mv apache-maven-* maven && \
ln -s /usr/share/maven/bin/mvn /bin/

Exercise the application as described above.

WORKDIR /helidon

# Create a first layer to cache the "Maven World" in the local repository.
ADD pom.xml .
RUN mvn package -Dmaven.test.skip -Declipselink.weave.skip -DskipOpenApiGenerate

# Do the Maven build with fat JAR!
ADD src src
RUN mvn package -DskipTests

# 2nd stage, build the runtime image
FROM container-registry.oracle.com/java/jdk-no-fee-term:21
WORKDIR /helidon

# Copy ONLY the fat JAR (not libs directory)
COPY --from=build /helidon/target/*.jar app.jar

# Simple fat JAR execution
CMD ["java", "-jar", "app.jar"]
EXPOSE 8080
```
42 changes: 42 additions & 0 deletions cloudbank-v4/customer-helidon/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,11 @@
<artifactId>jakarta.persistence-api</artifactId>
<!-- <scope>provided</scope> -->
</dependency>
<dependency>
<groupId>io.helidon.integrations.eureka</groupId>
<artifactId>helidon-integrations-eureka</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>io.helidon.integrations.cdi</groupId>
<artifactId>helidon-integrations-cdi-jpa</artifactId>
Expand All @@ -58,6 +63,11 @@
<artifactId>hibernate-core</artifactId>
<version>${version.lib.hibernate}</version>
</dependency>
<!--dependency>
<groupId>io.helidon.logging</groupId>
<artifactId>helidon-logging-jul</artifactId>
<scope>runtime</scope>
</dependency-->
<dependency>
<groupId>io.helidon.microprofile.openapi</groupId>
<artifactId>helidon-microprofile-openapi</artifactId>
Expand Down Expand Up @@ -153,6 +163,38 @@
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>3.4.2</version>
<configuration>
<descriptors>
<descriptor>src/assembly/jib-ready.xml</descriptor>
</descriptors>
</configuration>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- Explicitly set the correct main class for Helidon MP -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<classpathPrefix>libs/</classpathPrefix>
<mainClass>io.helidon.microprofile.cdi.Main</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
<plugin>
<groupId>org.hibernate.orm.tooling</groupId>
<artifactId>hibernate-enhance-maven-plugin</artifactId>
Expand Down
24 changes: 24 additions & 0 deletions cloudbank-v4/customer-helidon/src/assembly/jib-ready.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<assembly>
<id>deployment</id>
<formats>
<format>zip</format>
</formats>
<includeBaseDirectory>false</includeBaseDirectory>
<fileSets>
<!-- Copy the main JAR to root of ZIP -->
<fileSet>
<directory>${project.build.directory}</directory>
<includes>
<include>${project.build.finalName}.jar</include>
</includes>
<outputDirectory>.</outputDirectory>
<fileMode>755</fileMode>
</fileSet>
<!-- Copy dependencies to app/libs in ZIP -->
<fileSet>
<directory>${project.build.directory}/libs</directory>
<outputDirectory>app/libs</outputDirectory>
<fileMode>644</fileMode>
</fileSet>
</fileSets>
</assembly>
Loading