Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#2270: External DB Support #2457

Merged
merged 11 commits into from
Jan 6, 2025
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
25 changes: 25 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,29 @@ sourceSets {

}
}

test {
java {
if (System.getenv("DOCKER_ENABLE_SECURITY") == "false") {
exclude "stirling/software/SPDF/config/security/**"
exclude "stirling/software/SPDF/controller/api/UserControllerTest.java"
exclude "stirling/software/SPDF/controller/api/DatabaseControllerTest.java"
exclude "stirling/software/SPDF/controller/web/AccountWebControllerTest.java"
exclude "stirling/software/SPDF/controller/web/DatabaseWebControllerTest.java"
exclude "stirling/software/SPDF/model/ApiKeyAuthenticationTokenTest.java"
exclude "stirling/software/SPDF/model/AttemptCounterTest.java"
exclude "stirling/software/SPDF/model/AuthorityTest.java"
exclude "stirling/software/SPDF/model/PersistentLoginTest.java"
exclude "stirling/software/SPDF/model/SessionEntityTest.java"
exclude "stirling/software/SPDF/model/UserTest.java"
exclude "stirling/software/SPDF/repository/**"
}

if (System.getenv("STIRLING_PDF_DESKTOP_UI") == "false") {
exclude "stirling/software/SPDF/UI/impl/**"
}
}
}
}

openApi {
Expand Down Expand Up @@ -299,10 +322,12 @@ dependencies {
implementation "org.springframework.boot:spring-boot-starter-oauth2-client:$springBootVersion"

implementation "org.springframework.session:spring-session-core:$springBootVersion"
implementation "org.springframework:spring-jdbc:6.2.1"

implementation 'com.unboundid.product.scim2:scim2-sdk-client:2.3.5'
// Don't upgrade h2database
runtimeOnly "com.h2database:h2:2.3.232"
runtimeOnly "org.postgresql:postgresql:42.7.4"
constraints {
implementation "org.opensaml:opensaml-core:$openSamlVersion"
implementation "org.opensaml:opensaml-saml-api:$openSamlVersion"
Expand Down
63 changes: 63 additions & 0 deletions exampleYmlFiles/docker-compose-latest-fat-security-postgres.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
services:
stirling-pdf:
container_name: Stirling-PDF-Security-Fat-Postgres
image: stirlingtools/stirling-pdf:latest-fat-postgres
deploy:
resources:
limits:
memory: 4G
depends_on:
- db
healthcheck:
test: [ "CMD-SHELL", "curl -f http://localhost:8080/api/v1/info/status | grep -q 'UP'" ]
interval: 5s
timeout: 10s
retries: 16
ports:
- 8080:8080
volumes:
- ./stirling/latest/data:/usr/share/tessdata:rw
- ./stirling/latest/config:/configs:rw
- ./stirling/latest/logs:/logs:rw
environment:
DOCKER_ENABLE_SECURITY: "true"
SECURITY_ENABLELOGIN: "false"
PUID: 1002
PGID: 1002
UMASK: "022"
SYSTEM_DEFAULTLOCALE: en-US
UI_APPNAME: Stirling-PDF
UI_HOMEDESCRIPTION: Demo site for Stirling-PDF Latest-fat with Security and PostgreSQL
UI_APPNAMENAVBAR: Stirling-PDF Latest-fat-PostgreSQL
SYSTEM_MAXFILESIZE: "100"
METRICS_ENABLED: "true"
SYSTEM_GOOGLEVISIBILITY: "true"
SYSTEM_DATASOURCE_ENABLECUSTOMDATABASE: "true"
SYSTEM_DATASOURCE_CUSTOMDATABASEURL: "jdbc:postgresql://db:5432/stirling_pdf"
SYSTEM_DATASOURCE_USERNAME: "admin"
SYSTEM_DATASOURCE_PASSWORD: "stirling"
restart: on-failure:5

db:
image: 'postgres:17.2-alpine'
restart: on-failure:5
container_name: db
ports:
- "5432:5432"
environment:
POSTGRES_DB: "stirling_pdf"
POSTGRES_USER: "admin"
POSTGRES_PASSWORD: "stirling"
shm_size: "512mb"
deploy:
resources:
limits:
memory: 512m
cpus: "0.5"
healthcheck:
test: [ "CMD-SHELL", "pg_isready -U admin stirling_pdf" ]
interval: 1s
timeout: 5s
retries: 10
volumes:
- ./stirling/latest/data:/pgdata
6 changes: 3 additions & 3 deletions exampleYmlFiles/docker-compose-latest-fat-security.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ services:
ports:
- 8080:8080
volumes:
- /stirling/latest/data:/usr/share/tessdata:rw
- /stirling/latest/config:/configs:rw
- /stirling/latest/logs:/logs:rw
- ./stirling/latest/data:/usr/share/tessdata:rw
- ./stirling/latest/config:/configs:rw
- ./stirling/latest/logs:/logs:rw
environment:
DOCKER_ENABLE_SECURITY: "true"
SECURITY_ENABLELOGIN: "false"
Expand Down
6 changes: 3 additions & 3 deletions exampleYmlFiles/docker-compose-latest-security.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ services:
ports:
- "8080:8080"
volumes:
- /stirling/latest/data:/usr/share/tessdata:rw
- /stirling/latest/config:/configs:rw
- /stirling/latest/logs:/logs:rw
- ./stirling/latest/data:/usr/share/tessdata:rw
- ./stirling/latest/config:/configs:rw
- ./stirling/latest/logs:/logs:rw
environment:
DOCKER_ENABLE_SECURITY: "true"
SECURITY_ENABLELOGIN: "true"
Expand Down
10 changes: 5 additions & 5 deletions src/main/java/stirling/software/SPDF/EE/LicenseKeyChecker.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ public class LicenseKeyChecker {

private final ApplicationProperties applicationProperties;

private boolean enterpriseEnbaledResult = false;
private boolean enterpriseEnabledResult = false;

@Autowired
public LicenseKeyChecker(
Expand All @@ -35,12 +35,12 @@ public void checkLicensePeriodically() {

private void checkLicense() {
if (!applicationProperties.getEnterpriseEdition().isEnabled()) {
enterpriseEnbaledResult = false;
enterpriseEnabledResult = false;
} else {
enterpriseEnbaledResult =
enterpriseEnabledResult =
licenseService.verifyLicense(
applicationProperties.getEnterpriseEdition().getKey());
if (enterpriseEnbaledResult) {
if (enterpriseEnabledResult) {
log.info("License key is valid.");
} else {
log.info("License key is invalid.");
Expand All @@ -55,6 +55,6 @@ public void updateLicenseKey(String newKey) throws IOException {
}

public boolean getEnterpriseEnabledResult() {
return enterpriseEnbaledResult;
return enterpriseEnabledResult;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,21 +28,22 @@
import stirling.software.SPDF.config.InstallationPathConfig;
import stirling.software.SPDF.model.ApplicationProperties;

@SpringBootApplication
@EnableScheduling
@Slf4j
public class SPdfApplication {
@EnableScheduling
@SpringBootApplication
public class SPDFApplication {

private static String baseUrlStatic;
private static String serverPortStatic;
private static String baseUrlStatic;

private final Environment env;
private final ApplicationProperties applicationProperties;
private final WebBrowser webBrowser;

@Value("${baseUrl:http://localhost}")
private String baseUrl;

public SPdfApplication(
public SPDFApplication(
Environment env,
ApplicationProperties applicationProperties,
@Autowired(required = false) WebBrowser webBrowser) {
Expand All @@ -51,42 +52,28 @@ public SPdfApplication(
this.webBrowser = webBrowser;
}

// Optionally keep this method if you want to provide a manual port-incrementation fallback.
private static String findAvailablePort(int startPort) {
int port = startPort;
while (!isPortAvailable(port)) {
port++;
}
return String.valueOf(port);
}

private static boolean isPortAvailable(int port) {
try (ServerSocket socket = new ServerSocket(port)) {
return true;
} catch (IOException e) {
return false;
}
}

public static void main(String[] args) throws IOException, InterruptedException {
SpringApplication app = new SpringApplication(SPdfApplication.class);
SpringApplication app = new SpringApplication(SPDFApplication.class);

Properties props = new Properties();

if (Boolean.parseBoolean(System.getProperty("STIRLING_PDF_DESKTOP_UI", "false"))) {
System.setProperty("java.awt.headless", "false");
app.setHeadless(false);
props.put("java.awt.headless", "false");
props.put("spring.main.web-application-type", "servlet");
}
app.setAdditionalProfiles("default");

app.setAdditionalProfiles(getActiveProfile(args));

ConfigInitializer initializer = new ConfigInitializer();
try {
initializer.ensureConfigExists();
} catch (IOException | URISyntaxException e) {
log.error("Error initialising configuration", e);
}

Map<String, String> propertyFiles = new HashMap<>();

// External config files
log.info("Settings file: {}", InstallationPathConfig.getSettingsPath());
if (Files.exists(Paths.get(InstallationPathConfig.getSettingsPath()))) {
Expand All @@ -98,6 +85,7 @@ public static void main(String[] args) throws IOException, InterruptedException
"External configuration file '{}' does not exist.",
InstallationPathConfig.getSettingsPath());
}

if (Files.exists(Paths.get(InstallationPathConfig.getCustomSettingsPath()))) {
String existingLocation =
propertyFiles.getOrDefault("spring.config.additional-location", "");
Expand All @@ -113,50 +101,30 @@ public static void main(String[] args) throws IOException, InterruptedException
InstallationPathConfig.getCustomSettingsPath());
}
Properties finalProps = new Properties();

if (!propertyFiles.isEmpty()) {
finalProps.putAll(
Collections.singletonMap(
"spring.config.additional-location",
propertyFiles.get("spring.config.additional-location")));
}

if (!props.isEmpty()) {
finalProps.putAll(props);
}
app.setDefaultProperties(finalProps);

app.run(args);

// Ensure directories are created
try {
Files.createDirectories(Path.of(InstallationPathConfig.getTemplatesPath()));
Files.createDirectories(Path.of(InstallationPathConfig.getStaticPath()));
} catch (Exception e) {
log.error("Error creating directories: {}", e.getMessage());
}
printStartupLogs();
}

private static void printStartupLogs() {
log.info("Stirling-PDF Started.");
String url = baseUrlStatic + ":" + getStaticPort();
log.info("Navigate to {}", url);
}

public static String getStaticBaseUrl() {
return baseUrlStatic;
}

public static String getStaticPort() {
return serverPortStatic;
}

@Value("${server.port:8080}")
public void setServerPortStatic(String port) {
if ("auto".equalsIgnoreCase(port)) {
// Use Spring Boot's automatic port assignment (server.port=0)
SPdfApplication.serverPortStatic = // This will let Spring Boot assign an available port
"0";
} else {
SPdfApplication.serverPortStatic = port;
}
printStartupLogs();
}

@PostConstruct
Expand Down Expand Up @@ -189,17 +157,73 @@ public void init() {
log.info("Running configs {}", applicationProperties.toString());
}

@Value("${server.port:8080}")
public void setServerPortStatic(String port) {
if ("auto".equalsIgnoreCase(port)) {
// Use Spring Boot's automatic port assignment (server.port=0)
SPDFApplication.serverPortStatic =
"0"; // This will let Spring Boot assign an available port
} else {
SPDFApplication.serverPortStatic = port;
}
}

@PreDestroy
public void cleanup() {
if (webBrowser != null) {
webBrowser.cleanup();
}
}

private static void printStartupLogs() {
log.info("Stirling-PDF Started.");
String url = baseUrlStatic + ":" + getStaticPort();
log.info("Navigate to {}", url);
}

private static String[] getActiveProfile(String[] args) {
DarioGii marked this conversation as resolved.
Show resolved Hide resolved
if (args == null) {
return new String[] {"default"};
}

for (String arg : args) {
if (arg.contains("spring.profiles.active")) {
return arg.substring(args[0].indexOf('=') + 1).split(", ");
}
}

return new String[] {"default"};
}

private static boolean isPortAvailable(int port) {
try (ServerSocket socket = new ServerSocket(port)) {
return true;
} catch (IOException e) {
return false;
}
}

// Optionally keep this method if you want to provide a manual port-incrementation fallback.
private static String findAvailablePort(int startPort) {
int port = startPort;
while (!isPortAvailable(port)) {
port++;
}
return String.valueOf(port);
}

public static String getStaticBaseUrl() {
return baseUrlStatic;
}

public String getNonStaticBaseUrl() {
return baseUrlStatic;
}

public static String getStaticPort() {
return serverPortStatic;
}

public String getNonStaticPort() {
return serverPortStatic;
}
Expand Down

This file was deleted.

Loading
Loading