Skip to content

Commit 4021a5d

Browse files
committed
Convert to Spring Boot
1 parent 730c53c commit 4021a5d

35 files changed

+410
-1006
lines changed

.github/workflows/gcr-deploy.yaml

Lines changed: 25 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,67 +1,64 @@
1-
name: build
1+
name: deploy
22

33
on:
44
push:
55
branches:
66
- main
77

8+
workflow_dispatch:
9+
810
# Environment variables available to all jobs and steps in this workflow
11+
# NOTE: these aren't really secret, but there aren't non-secret settings
912
env:
1013
RUN_PROJECT: ${{ secrets.RUN_PROJECT }}
1114
RUN_REGION: ${{ secrets.RUN_REGION }}
1215
RUN_SERVICE: ${{ secrets.RUN_SERVICE }}
1316

1417
jobs:
15-
setup-build-deploy:
16-
name: Setup, Build, and Deploy
18+
deploy:
19+
name: Deploy to CloudRun
1720
runs-on: ubuntu-latest
1821

1922
steps:
2023
- name: Checkout
21-
uses: actions/checkout@v1
24+
uses: actions/checkout@v4
2225

23-
- name: Set up JDK 1.8
24-
uses: actions/setup-java@v1
26+
- name: gcloud auth
27+
id: 'auth'
28+
uses: 'google-github-actions/auth@v2'
2529
with:
26-
java-version: 1.8
27-
28-
- name: Set COMMIT and LASTMOD
29-
run: |
30-
sudo apt-get install -y xmlstarlet
31-
xmlstarlet edit --inplace --update "//_:web-app/_:context-param/_:param-name[text()='COMMIT']/parent::*/_:param-value" -v ${GITHUB_SHA:0:7} www/WEB-INF/web.xml
32-
xmlstarlet edit --inplace --update "//_:web-app/_:context-param/_:param-name[text()='LASTMOD']/parent::*/_:param-value" -v "$(date -u +%Y-%m-%dT%H:%M:%SZ)" www/WEB-INF/web.xml
30+
credentials_json: '${{ secrets.GCP_SA_KEY }}'
3331

3432
# Setup gcloud CLI
35-
- uses: GoogleCloudPlatform/github-actions/setup-gcloud@master
36-
with:
37-
version: '275.0.0'
38-
service_account_email: ${{ secrets.GCP_SA_EMAIL }}
39-
service_account_key: ${{ secrets.GCP_SA_KEY }}
33+
- name: gcloud setup
34+
uses: google-github-actions/setup-gcloud@v2
4035

41-
# Configure gcloud CLI
42-
- name: gcloud Set up
43-
run: |
44-
gcloud config set project $RUN_PROJECT
36+
- name: gcloud docker-auth
37+
run: gcloud auth configure-docker
4538

4639
# Build and push image to Google Container Registry
47-
- name: Docker Build
40+
- name: Build
4841
run: |
49-
docker build -t gcr.io/$RUN_PROJECT/$RUN_SERVICE:$GITHUB_SHA .
42+
docker build \
43+
--build-arg COMMIT=${GITHUB_SHA:0:7} \
44+
--build-arg LASTMOD=$(date -u +%Y-%m-%dT%H:%M:%SZ) \
45+
--tag gcr.io/${RUN_PROJECT}/${RUN_SERVICE}:$GITHUB_SHA \
46+
.
5047
5148
- name: GCloud auth to docker
5249
run: |
5350
gcloud auth configure-docker
5451
5552
- name: Push to registry
5653
run: |
57-
docker push gcr.io/$RUN_PROJECT/$RUN_SERVICE:$GITHUB_SHA
54+
docker push gcr.io/${RUN_PROJECT}/${RUN_SERVICE}:$GITHUB_SHA
5855
5956
# Deploy image to Cloud Run
6057
- name: Deploy
6158
run: |
62-
gcloud run deploy $RUN_SERVICE \
59+
gcloud run deploy ${RUN_SERVICE} \
6360
--allow-unauthenticated \
64-
--image gcr.io/$RUN_PROJECT/$RUN_SERVICE:$GITHUB_SHA \
61+
--image gcr.io/${RUN_PROJECT}/${RUN_SERVICE}:$GITHUB_SHA \
6562
--platform managed \
6663
--project ${RUN_PROJECT} \
67-
--region $RUN_REGION
64+
--region ${RUN_REGION}

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
11
*~
22
*.class
3+
.DS_Store
4+
*.env*
35
.idea/
6+
target
7+
.vscode

Dockerfile

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,25 @@
1-
FROM jetty
1+
FROM maven:3.9.9-eclipse-temurin-21 AS builder
22

3-
COPY ./www /var/lib/jetty/webapps/ROOT
3+
WORKDIR /app
4+
COPY pom.xml /app
5+
6+
RUN mvn dependency:go-offline
7+
8+
COPY . /app
9+
RUN mvn package
10+
11+
12+
FROM gcr.io/distroless/java21-debian12
13+
ARG COMMIT="(not set)"
14+
ARG LASTMOD="(not set)"
15+
ENV COMMIT=$COMMIT
16+
ENV LASTMOD=$LASTMOD
17+
18+
WORKDIR /app
19+
20+
COPY --from=builder /app/target/ff-pdf2txt-1.0.jar /app/ff-pdf2txt-1.0.jar
21+
22+
USER nonroot
23+
EXPOSE 4000
24+
ENV PORT=4000
25+
CMD ["ff-pdf2txt-1.0.jar"]

build.xml

Lines changed: 0 additions & 52 deletions
This file was deleted.

docker-run.sh

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,21 @@
1-
#!/bin/bash
1+
#!/usr/bin/env bash
2+
#
3+
# run locally but in docker
24

35
set -o errexit
46
set -o pipefail
57
set -o nounset
68

7-
docker build -t ff-pdf2txt:latest .
8-
docker run -p 4000:8080 ff-pdf2txt:latest
9+
APP=ff-pdf2txt
10+
11+
docker build \
12+
--build-arg COMMIT=$(git rev-parse --short HEAD)-local \
13+
--build-arg LASTMOD=$(date -u +%Y-%m-%dT%H:%M:%SZ) \
14+
--tag "${APP}" \
15+
.
16+
17+
docker run \
18+
--publish 4000:4000 \
19+
--expose 4000 \
20+
--env PORT='4000' \
21+
"${APP}"

pom.xml

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
4+
<modelVersion>4.0.0</modelVersion>
5+
6+
<groupId>info.fileformat.pdf2txt</groupId>
7+
<artifactId>ff-pdf2txt</artifactId>
8+
<version>1.0</version>
9+
10+
<parent>
11+
<groupId>org.springframework.boot</groupId>
12+
<artifactId>spring-boot-starter-parent</artifactId>
13+
<version>3.4.4</version>
14+
</parent>
15+
16+
<dependencies>
17+
<dependency>
18+
<groupId>org.springframework.boot</groupId>
19+
<artifactId>spring-boot-starter-web</artifactId>
20+
</dependency>
21+
<dependency>
22+
<groupId>org.springframework.boot</groupId>
23+
<artifactId>spring-boot-devtools</artifactId>
24+
<optional>true</optional>
25+
</dependency>
26+
<!-- https://mvnrepository.com/artifact/org.apache.pdfbox/pdfbox -->
27+
<dependency>
28+
<groupId>org.apache.pdfbox</groupId>
29+
<artifactId>pdfbox</artifactId>
30+
<version>3.0.4</version>
31+
</dependency>
32+
</dependencies>
33+
34+
<build>
35+
<plugins>
36+
<plugin>
37+
<groupId>org.springframework.boot</groupId>
38+
<artifactId>spring-boot-maven-plugin</artifactId>
39+
</plugin>
40+
</plugins>
41+
</build>
42+
43+
</project>

run.sh

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,16 @@
1-
#!/bin/bash
1+
#!/usr/bin/env bash
22
#
3-
# run the app in a local docker container
3+
# script to run on localhost
44
#
55

66
set -o errexit
77
set -o pipefail
88
set -o nounset
99

10-
echo "INFO: starting"
10+
ENV_FILE="${1:-./.env}"
11+
if [ -f "${ENV_FILE}" ]; then
12+
echo "INFO: loading '${ENV_FILE}'!"
13+
export $(cat "${ENV_FILE}")
14+
fi
1115

12-
docker run \
13-
--publish 4000:8080 \
14-
--volume /tmp/jetty \
15-
--volume /run/jetty \
16-
--volume "${PWD}/www:/var/lib/jetty/webapps/ROOT" \
17-
jetty:9.4.30-jdk14
16+
mvn spring-boot:run
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
package info.fileformat.pdf2txt;
2+
3+
import org.springframework.boot.web.servlet.error.ErrorController;
4+
import org.springframework.stereotype.Controller;
5+
import org.springframework.web.bind.annotation.RequestMapping;
6+
import org.springframework.web.util.UrlPathHelper;
7+
8+
import java.util.LinkedHashMap;
9+
import java.util.Map;
10+
import java.util.regex.Pattern;
11+
12+
@Controller
13+
public class CustomErrorController implements ErrorController {
14+
15+
static final Pattern callbackPattern = Pattern.compile("([&]|^)callback=([^&]+)");
16+
17+
@RequestMapping("/error")
18+
public void handleError(jakarta.servlet.http.HttpServletRequest req,
19+
jakarta.servlet.http.HttpServletResponse resp) throws java.io.IOException {
20+
Object status = req.getAttribute("jakarta.servlet.error.status_code");
21+
22+
23+
String callback = null;
24+
String qs = UrlPathHelper.defaultInstance.getOriginatingQueryString(req);
25+
if (qs != null) {
26+
java.util.regex.Matcher matcher = callbackPattern.matcher(qs);
27+
if (matcher.find()) {
28+
callback = matcher.group(2);
29+
}
30+
}
31+
32+
Integer statusCode = 500;
33+
if (status != null) {
34+
statusCode = Integer.valueOf(status.toString());
35+
} else {
36+
// LATER: warning message
37+
//System.out.println("No status code found in request");
38+
}
39+
40+
String message = (String) req.getAttribute("jakarta.servlet.error.message");
41+
if (message == null || message.length() == 0) {
42+
//System.out.println("No error message found in request");
43+
44+
Object ex = req.getAttribute("jakarta.servlet.error.exception");
45+
if (ex != null && ex instanceof Throwable) {
46+
Throwable throwable = (Throwable) ex;
47+
message = throwable.getMessage();
48+
} else {
49+
message = "Server Error";
50+
}
51+
}
52+
resp.setStatus(statusCode);
53+
Map<String, Object> retVal = new LinkedHashMap<>();
54+
retVal.put("success", Boolean.FALSE);
55+
retVal.put("code", statusCode);
56+
retVal.put("message", message);
57+
58+
HandleJsonp.handleJsonp(resp, callback, retVal);
59+
}
60+
61+
public String getErrorPath() {
62+
return "/error";
63+
}
64+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package info.fileformat.pdf2txt;
2+
3+
import java.io.PrintWriter;
4+
import java.util.Map;
5+
6+
import com.fasterxml.jackson.databind.ObjectMapper;
7+
8+
public class HandleJsonp {
9+
10+
public static void handleJsonp(
11+
jakarta.servlet.http.HttpServletResponse resp,
12+
String callback,
13+
Map<String, Object> retVal
14+
) throws java.io.IOException {
15+
16+
ObjectMapper objectMapper = new ObjectMapper();
17+
String jsonResponse = objectMapper.writeValueAsString(retVal);
18+
19+
if (callback != null && callback.matches("^[a-zA-Z_][a-zA-Z0-9_]*$")) {
20+
resp.setContentType("application/javascript");
21+
resp.setCharacterEncoding("UTF-8");
22+
PrintWriter writer = resp.getWriter();
23+
writer.write(callback);
24+
writer.write("(");
25+
writer.write(jsonResponse);
26+
writer.write(");");
27+
} else {
28+
resp.setHeader("Access-Control-Allow-Origin", "*");
29+
resp.setHeader("Access-Control-Allow-Methods", "GET, POST");
30+
resp.setHeader("Access-Control-Max-Age", "604800");
31+
resp.setContentType("application/json");
32+
resp.setCharacterEncoding("UTF-8");
33+
resp.getWriter().write(jsonResponse);
34+
}
35+
}
36+
}

0 commit comments

Comments
 (0)