Compare commits

...
Sign in to create a new pull request.

78 commits

Author SHA1 Message Date
1476c9b19f Merge branch 'main' into renovate/major-jetty-packages
All checks were successful
Build / build (push) Successful in 35s
2025-05-27 17:55:54 +00:00
df28d40645 Update dependency gradle to v8.14.1
All checks were successful
Build / build (push) Successful in 33s
2025-05-25 15:39:15 +00:00
29f7ca5ae3 Merge branch 'main' into renovate/major-jetty-packages
All checks were successful
Build / build (push) Successful in 8s
2025-05-25 15:37:13 +00:00
3f2bf9c3dc
Simplify repository workflows
All checks were successful
Build / build (push) Successful in 31s
* Use deploy workflow for staging, too
* Reduce deploy.sh script
2025-05-25 17:05:05 +02:00
f9bc64d1ed
Merge remote-tracking branch 'origin/main' into renovate/major-jetty-packages 2025-05-24 21:41:38 +02:00
f6668636a9 Replace hard-coded hostname with input 2025-05-24 19:25:08 +00:00
1001b3b503 Replace hard-coded hostname with input 2025-05-24 19:14:30 +00:00
96ceb1d5f3
Merge branch 'main' into renovate/major-jetty-packages 2025-05-24 15:39:44 +02:00
27cdc5104b
Reorganize and refurbish .gitignore file 2025-04-11 20:51:55 +02:00
745ce5bfca
Merge branch 'main' into renovate/major-jetty-packages 2025-04-11 13:22:10 +02:00
c4abd27ac7
Make deploy script executable
All checks were successful
Build / build (push) Successful in 11s
2025-04-11 12:41:44 +02:00
6b88318bcd
Fix regression of Java sources not being processed before compiling
All checks were successful
Build / build (push) Successful in 11s
2025-04-11 11:48:32 +02:00
0cf9cf7af2
Merge remote-tracking branch 'origin/main' into renovate/major-jetty-packages
All checks were successful
Build / build (push) Successful in 10s
2025-04-10 23:32:50 +02:00
96f2dce50f
Add launch configuration for debugging Helma
All checks were successful
Build / build (push) Successful in 34s
2025-04-08 12:05:54 +02:00
f786b40961
Rename the modules project to prevent VSC from renaming the main project to helma_
Does not work, unfortunately
2025-04-08 12:04:55 +02:00
8caf790529
Remove custom configuration of Gradle sourceSets
Using the sources in build creates a lot of confusion in VSC
2025-04-08 12:04:54 +02:00
e6c974120b
Update .gitigore file for VSC settings 2025-04-08 12:04:53 +02:00
6723df912e
Resolve FIXME but without fixing the issue
All checks were successful
Build / build (push) Successful in 19s
I tried to make this work but it might need a more thorough rewrite that I just cannot do.

The worst that can happen is stopping and starting Helma apps adding redundant ServletContextHandlers to the ContextHandlerCollection until Helma is restarted.
2025-04-07 17:16:59 +02:00
436862e87a
Remove setting of “empty” base resource
Fingers crossed it won’t be missed
2025-04-07 17:16:58 +02:00
36a12effb2
Bump Jetty versions to 12.0.19 2025-04-07 17:16:57 +02:00
2994a4becc
Disable Jetty’s session cookies
This remediates the exception “Shared scheduler not started” and restores the functionality of enabling an app in apps.properties – see #103 (comment)
2025-04-07 17:16:53 +02:00
99e8b204fd
Bump Java version 2025-04-07 17:05:43 +02:00
c42c0a7a17
Update repo URL 2025-04-07 17:05:43 +02:00
b7543cf615
Bump year of copyright notice 2025-04-07 17:05:42 +02:00
fc084f6e52
Escape HTML elements in commit messages 2025-04-07 17:05:41 +02:00
6fc73d2320
Add release notes generated with git-cliff 2025-04-07 17:05:40 +02:00
9b5cc988dd
Run the build workflow when itself has changed 2025-04-07 17:05:40 +02:00
04b210b464
Leave aside compiling for different Java versions for now 2025-04-07 17:05:39 +02:00
4c011f1e1b
Gradle is installed on the runner 2025-04-07 17:05:38 +02:00
bc7894ecc1
Use fully qualified URL for setup-java action 2025-04-07 17:05:38 +02:00
a3fbf72f38
Initial commit 2025-04-07 17:05:37 +02:00
de2150693f
Add deploy script usable with rsync and a restricted SSH key 2025-04-07 17:05:36 +02:00
38181e8e00
Update repo URL 2025-03-01 19:32:20 +01:00
8adbd23569
Bump year of copyright notice 2025-03-01 19:32:06 +01:00
e3a7732837
Escape HTML elements in commit messages 2025-03-01 19:21:42 +01:00
d9d3c9b863
Add release notes generated with git-cliff
All checks were successful
Release / release (push) Successful in 31s
2025-03-01 16:57:02 +01:00
808bc48ab9
Run the build workflow when itself has changed
All checks were successful
Build / build (push) Successful in 23s
2025-02-28 22:15:00 +01:00
6ebdd6aa31
Leave aside compiling for different Java versions for now 2025-02-28 22:15:00 +01:00
2ff29317e5
Gradle is installed on the runner 2025-02-28 22:09:55 +01:00
84333d05cd
Use fully qualified URL for setup-java action 2025-02-28 22:04:48 +01:00
3a8997ca5c
Initial commit
Some checks failed
Build / build (11) (push) Failing after 0s
Build / build (17) (push) Failing after 0s
Build / build (21) (push) Failing after 0s
2025-02-28 21:58:08 +01:00
8212600d40
Add deploy script usable with rsync and a restricted SSH key 2025-02-28 21:43:19 +01:00
cd8baa4ac1
Merge branch 'main' into renovate/major-jetty-packages 2025-02-15 20:43:32 +01:00
1bb5a093da
Re-enable creating the release at Github after install of gh client
All checks were successful
Release / build (push) Successful in 26s
2025-02-15 19:49:13 +01:00
2c6dd96cd7
Merge branch 'main' into renovate/commons-codec-commons-codec-1.x 2025-02-15 18:39:26 +01:00
6f6ea55b7b Update dependency com.google.code.gson:gson to v2.12.1 2025-02-15 17:36:51 +00:00
b1a14ad87b Update dependency commons-logging:commons-logging to v1.3.5 2025-02-15 17:36:40 +00:00
d1ead6e081 Update Jetty packages to v9.4.57.v20241219 2025-02-15 17:36:29 +00:00
94557dd28e Update dependency gradle to v8.12.1 2025-02-15 17:35:46 +00:00
e2e67cf2cc Update dependency commons-codec:commons-codec to v1.18.0 2025-01-27 18:13:44 +00:00
11b226b272
Merge branch 'main' into origin/renovate/major-jetty-packages
# Conflicts:
#	build.gradle
2025-01-10 20:09:53 +01:00
1925916220
Bump required minimum Java version to 17 2024-06-15 18:27:30 +02:00
b1296fb093
Merge branch 'helma-🐜' into renovate/major-jetty-packages
# Conflicts:
#	.github/workflows/release.yml
2024-06-15 18:18:25 +02:00
51bc14c3a4
Remove over-complicated launch and tasks configuration in favor of Gradle plugin
Starting run/debug tasks with the plugin works out of the box;
one just has to avoid the default “Run and Debug” button.
2024-06-15 18:01:30 +02:00
3e5af064b0
Add setup for Gradle debugging in VS Codium 2024-06-15 18:00:59 +02:00
6401300189
Decouple update task from install
Now that Gradle runs Helma with the configured dependencies, updating the installation directory has become less crucial
2024-06-15 13:02:11 +02:00
45b19e3217
Reorder the tasks 2024-06-15 12:38:04 +02:00
ffb259a01c
Slightly modify the version string (still a date representation) 2024-06-15 12:37:16 +02:00
84abcde037
Update run configuration to always use the correct dependencies 2024-06-15 12:34:51 +02:00
9e870e6cd3
Slightly modify the format of the build date 2024-06-15 12:34:50 +02:00
1e32c8eb89
Merge remote-tracking branch 'origin/helma-🐜' into renovate/major-jetty-packages 2024-05-30 19:22:11 +02:00
9143faf35e
Add release action 2024-05-30 19:10:13 +02:00
79d83389f2
Use canonical paths when creating static contexts 2024-05-25 18:28:43 +02:00
90e45c9115
Migrate to Apache file upload API 2 w/ Jakarta 2024-05-25 18:28:43 +02:00
3dbcd792a6
Migrate to Jakarte servlet API 5 2024-05-25 18:28:42 +02:00
973b3493cb
Prevent java.lang.IllegalArgumentException: Resource String is invalid 2024-05-25 18:28:42 +02:00
441d952b35
Prevent incompatible types: ServletContextHandler cannot be converted to Handler 2024-05-25 18:28:42 +02:00
d67d0235bd
Prevent java.lang.IllegalStateException: Shared scheduler not started 2024-05-25 18:28:41 +02:00
fa59a27858
Fix creation of protected context 2024-05-25 18:28:41 +02:00
304ea4e456
Fix creation of app context 2024-05-25 18:28:40 +02:00
0165e7c80e
Fix setup of static resource 2024-05-25 18:28:40 +02:00
62630ae068
Modernize for loop 2024-05-25 18:28:39 +02:00
26975a109a
Method ServerConnector.setSoLingerTime() was removed 2024-05-25 18:28:39 +02:00
a943124d45
Fix creating Jetty server from config file 2024-05-25 18:28:38 +02:00
c087cb731e
Use correct version of Jetty servlet 2024-05-25 18:28:38 +02:00
c5f68013b1 Merge branch 'helma-🐜' into renovate/major-jetty-packages 2024-05-19 02:56:40 +02:00
ed575bc4c5
Update README.md
Minor edits
2024-05-19 02:05:49 +02:00
renovate[bot]
1cf738767c
Update Jetty packages 2024-05-18 15:30:36 +00:00
29 changed files with 297 additions and 150 deletions

22
.github/workflows/build.yml vendored Normal file
View file

@ -0,0 +1,22 @@
name: Build
on:
push:
paths:
- .github/workflows/build.yml
- build.gradle
- settings.gradle
- src/**
- launcher/build.gradle
- launcher/src/**
workflow_dispatch:
jobs:
build:
runs-on: antville
steps:
- uses: actions/checkout@v4
- name: Compile with Gradle
run: ./gradlew :compileJava

View file

@ -1,15 +1,39 @@
name: Deploy (Production) name: Deploy
on: workflow_dispatch on:
workflow_dispatch:
inputs:
hostname:
description: Hostname
type: string
required: true
default: antville.org
jobs: jobs:
deploy: stage:
runs-on: antville runs-on: antville
environment: environment:
name: antville.org name: production
url: https://antville.org url: ${{ inputs.hostname }}
steps: steps:
- name: Copy files to production server - uses: actions/checkout@v4
run: ssh staging-server deploy-helma
- name: Build with Gradle
run: ./gradlew installDist
- name: Copy build files to server
run: |
rsync ./build/install/helma/ ${{ inputs.hostname }}:./ \
--verbose --archive --delete --compress \
--filter '+ /bin' \
--filter '+ /extras' \
--filter '+ /launcher.jar' \
--filter '- /lib/ext' \
--filter '+ /lib' \
--filter '+ /modules' \
--filter '- /*'
- name: Restart Helma
run: ssh ${{ inputs.hostname }} restart

View file

@ -9,16 +9,27 @@ permissions:
contents: write contents: write
jobs: jobs:
build: release:
runs-on: antville runs-on: antville
env: env:
GH_TOKEN: ${{ github.token }} GH_TOKEN: ${{ secrets.GH_TOKEN }}
LC_TIME: en_US.UTF-8 LC_TIME: en_US.UTF-8
TODAY: $(date +'%d %b %Y')
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Create release notes
id: create_release_notes
run: |
release_notes=$(npx git-cliff@latest --latest)
# Write the release notes as a heredoc to the workflow output
# ⚠️ No white space around `<<` is crucial!
echo "release_notes<<.eot0x03" >> $GITHUB_OUTPUT
echo "$release_notes" >> $GITHUB_OUTPUT
echo ".eot0x03" >> $GITHUB_OUTPUT
- name: Build with Gradle - name: Build with Gradle
run: ./gradlew assembleDist run: ./gradlew assembleDist
@ -29,23 +40,20 @@ jobs:
direction: upload direction: upload
url: https://code.host.antville.org url: https://code.host.antville.org
token: ${{ github.token }} token: ${{ github.token }}
title: ${{ env.TODAY }} title: Helma ${{ github.ref_name }}
#tag: $(date +'%Y.%m.%d')
release-dir: build/distributions release-dir: build/distributions
release-notes-assistant: true release-notes: ${{ steps.create_release_notes.outputs.release_notes }}
verbose: true verbose: true
- name: Create release at GitHub - name: Create release at GitHub
# FIXME: Currently only outputs gh command; adapt for Forgejo
run: | run: |
echo gh release create "$GITHUB_REF_NAME" \ gh release create "$GITHUB_REF_NAME" \
--repo "$GITHUB_REPOSITORY" \ --repo "$GITHUB_REPOSITORY" \
--title "$(date +'%d %b %Y')" \ --title "Helma ${{ github.ref_name }}" \
--generate-notes --notes "${{ steps.create_release_notes.outputs.release_notes }}"
- name: Upload release assets to GitHub - name: Upload release assets to GitHub
# FIXME: Currently only outputs gh command; adapt for Forgejo
run: | run: |
echo gh release upload "$GITHUB_REF_NAME" \ gh release upload "$GITHUB_REF_NAME" build/distributions/helma-*.* \
build/distributions/helma-*.* \ --repo "$GITHUB_REPOSITORY" \
--clobber --clobber

View file

@ -1,32 +0,0 @@
name: Deploy (Staging)
on: workflow_dispatch
jobs:
stage:
runs-on: antville
environment:
name: stage
url: ${{ vars.stage_url }}
steps:
- uses: actions/checkout@v4
- name: Build with Gradle
run: ./gradlew installDist
- name: Publish to staging server
run: |
rsync ./build/install/helma/ staging-server:./ \
--verbose --archive --delete --compress \
--filter '+ /bin' \
--filter '+ /extras' \
--filter '+ /launcher.jar' \
--filter '- /lib/ext' \
--filter '+ /lib' \
--filter '+ /modules' \
--filter '- /*'
- name: Restart Helma
run: ssh staging-server restart

32
.gitignore vendored
View file

@ -1,22 +1,30 @@
.gradle # Generally ignore hidden files
.idea .*
.settings
build
/apps # Manage some Codium configuration
.vscode/*
!.vscode
!.vscode/extensions.json
!.vscode/launch.json
!.vscode/settings.json
!.vscode/tasks.json
# Ignore files created during build or run
/bin /bin
/backups /backups
/db build
/docs /docs
/extras
/lib /lib
/licenses /licenses
/log /log
# Ignore files managed in src/dist
/*.properties
/apps
/db
/extras
/launcher.jar
/static /static
/*.properties # Manage Gradle configuration
/launcher.jar
/passwd
/start.*
!/gradle.properties !/gradle.properties

View file

@ -1 +1 @@
11.0 17

21
.vscode/launch.json vendored Normal file
View file

@ -0,0 +1,21 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"type": "java",
"name": "Current File",
"request": "launch",
"mainClass": "${file}"
},
{
"type": "java",
"name": "Debug",
"request": "launch",
"mainClass": "helma.main.Server",
"projectName": "helma_"
}
]
}

View file

@ -1,6 +1,6 @@
# License # License
Copyright (c) 1999-2008 Helma Project. All rights reserved. Copyright (c) 1999-2025 Helma Project. All rights reserved.
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions modification, are permitted provided that the following conditions

View file

@ -2,8 +2,8 @@
## TL;DR ## TL;DR
- Make sure you have Java 11 or higher installed - Make sure you have Java 17 or higher installed
- Download and unpack the [latest release](https://github.com/antville/helma/releases) - Download and unpack the [latest release](https://code.host.antville.org/antville/helma/releases)
- Invoke `./bin/helma`, resp. `./bin/helma.bat`, depending on your platform - Invoke `./bin/helma`, resp. `./bin/helma.bat`, depending on your platform
- Direct your web browser to <http://localhost:8080> - Direct your web browser to <http://localhost:8080>

View file

@ -18,8 +18,8 @@ allprojects {
apply plugin: 'java' apply plugin: 'java'
java { java {
sourceCompatibility = JavaVersion.VERSION_11 sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_11 targetCompatibility = JavaVersion.VERSION_17
} }
repositories { repositories {
@ -42,15 +42,6 @@ if (JavaVersion.current().isJava8Compatible()) {
} }
} }
sourceSets {
main {
java {
// Sources in `src` will be available here after processing
srcDirs = ["$buildDir/src/main/java"]
}
}
}
configurations { configurations {
// Wrapping implementation because it does not allow access to its files // Wrapping implementation because it does not allow access to its files
// (i.e. cannot be resolved) // (i.e. cannot be resolved)
@ -58,16 +49,17 @@ configurations {
} }
dependencies { dependencies {
implementation 'com.google.code.gson:gson:2.11.0' implementation 'com.google.code.gson:gson:2.12.1'
implementation 'commons-codec:commons-codec:1.17.1' implementation 'commons-codec:commons-codec:1.18.0'
implementation 'commons-fileupload:commons-fileupload:1.5' implementation 'org.apache.commons:commons-fileupload2-core:2.0.0-M2'
implementation 'commons-logging:commons-logging:1.3.4' implementation 'org.apache.commons:commons-fileupload2-jakarta:2.0.0-M1'
implementation 'commons-logging:commons-logging:1.3.5'
implementation 'commons-net:commons-net:3.11.1' implementation 'commons-net:commons-net:3.11.1'
implementation 'com.sun.mail:javax.mail:1.6.2' implementation 'com.sun.mail:javax.mail:1.6.2'
implementation 'javax.servlet:javax.servlet-api:4.0.1' implementation 'jakarta.servlet:jakarta.servlet-api:5.0.0'
implementation 'org.ccil.cowan.tagsoup:tagsoup:1.2.1' implementation 'org.ccil.cowan.tagsoup:tagsoup:1.2.1'
implementation 'org.eclipse.jetty:jetty-servlet:9.4.56.v20240826' implementation 'org.eclipse.jetty.ee9:jetty-ee9-servlet:12.0.19'
implementation 'org.eclipse.jetty:jetty-xml:9.4.56.v20240826' implementation 'org.eclipse.jetty:jetty-xml:12.0.19'
implementation 'org.mozilla:rhino-all:1.8.0' implementation 'org.mozilla:rhino-all:1.8.0'
implementation 'org.sejda.imageio:webp-imageio:0.1.6' implementation 'org.sejda.imageio:webp-imageio:0.1.6'
implementation 'xerces:xercesImpl:2.12.2' implementation 'xerces:xercesImpl:2.12.2'
@ -156,9 +148,11 @@ installDist {
dependsOn build dependsOn build
} }
tasks.register('processSource', Sync) { def processSource = tasks.register('processSource', Sync) {
def gitOutput = new ByteArrayOutputStream() def gitOutput = new ByteArrayOutputStream()
outputs.dir "${project.buildDir}/src"
exec { exec {
commandLine 'git', 'rev-parse', '--short', 'HEAD' commandLine 'git', 'rev-parse', '--short', 'HEAD'
standardOutput = gitOutput standardOutput = gitOutput
@ -173,9 +167,11 @@ tasks.register('processSource', Sync) {
.replaceAll('__builddate__', new Date().format("d MMM yyyy")) .replaceAll('__builddate__', new Date().format("d MMM yyyy"))
.replaceAll('__commithash__', gitOutput.toString().trim()) .replaceAll('__commithash__', gitOutput.toString().trim())
.replaceAll('__version__', version) .replaceAll('__version__', version)
} into "${project.buildDir}/src" } into outputs.files.singleFile
} }
tasks.compileJava.source = processSource.map { it.outputs.files }
tasks.register('update') { tasks.register('update') {
dependsOn installDist dependsOn installDist

52
cliff.toml Normal file
View file

@ -0,0 +1,52 @@
# git-cliff ~ default configuration file
# https://git-cliff.org/docs/configuration
#
# Lines starting with "#" are comments.
# Configuration options are organized into tables and keys.
# See documentation for more information on available options.
[changelog]
trim = true
header = "## Changes"
body = """
{% for group, commits in commits | filter(attribute="merge_commit") | group_by(attribute="group") %}
### {{ group | striptags | trim | upper_first }}
{% for commit in commits %}
* [<tt>{{ commit.id | split(pat="") | slice(end=11) | join() }}</tt>]\
(https://code.host.antville.org/antville/helma/commit/{{ commit.id }}) \
{% if commit.breaking %}**Breaking:** {% endif %}\
{{ commit.message | split(pat="\\n") | first | upper_first | escape }}\
{% endfor %}
{% endfor %}
**Full Changelog:** [{{ previous.version }} {{ version }}]\
(https://code.host.antville.org/antville/helma/compare/\
{{ previous.version | urlencode }}..{{ version | urlencode }})\n\n
"""
footer = """
Generated by [git-cliff](https://git-cliff.org/).
"""
[git]
conventional_commits = false
filter_commits = false
filter_unconventional = false
protect_breaking_commits = false
sort_commits = "newest"
split_commits = false
topo_order = false
commit_parsers = [
{ message = "^Apply \\d+ suggestion", skip = true },
{ message = "^Merge .*(branch|dependabot|dependency|renovate)", skip = true },
{ message = "^Lock file maintenance", skip = true },
{ message = "yarn\\.lock", skip = true },
{ message = "^[Ff]ix", group = "<!-- 0 --> 🐛 Bug Fixes" },
{ field = "author.name", pattern = "[Rr]enovate|[Dd]ependabot", group = "<!-- 3 --> 📦 Dependency Updates" },
{ message = "^Merge pull request", group = "<!-- 1 --> 🔀 Merges" },
{ message = ".*", group = "<!-- 2 --> Uncategorized" },
]

Binary file not shown.

View file

@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-bin.zip distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.1-bin.zip
networkTimeout=10000 networkTimeout=10000
validateDistributionUrl=true validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME

6
gradlew vendored
View file

@ -114,7 +114,7 @@ case "$( uname )" in #(
NONSTOP* ) nonstop=true ;; NONSTOP* ) nonstop=true ;;
esac esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar CLASSPATH="\\\"\\\""
# Determine the Java command to use to start the JVM. # Determine the Java command to use to start the JVM.
@ -205,7 +205,7 @@ fi
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command: # Collect all arguments for the java command:
# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, # * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# and any embedded shellness will be escaped. # and any embedded shellness will be escaped.
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
# treated as '${Hostname}' itself on the command line. # treated as '${Hostname}' itself on the command line.
@ -213,7 +213,7 @@ DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
set -- \ set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \ "-Dorg.gradle.appname=$APP_BASE_NAME" \
-classpath "$CLASSPATH" \ -classpath "$CLASSPATH" \
org.gradle.wrapper.GradleWrapperMain \ -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
"$@" "$@"
# Stop when "xargs" is not available. # Stop when "xargs" is not available.

4
gradlew.bat vendored
View file

@ -70,11 +70,11 @@ goto fail
:execute :execute
@rem Setup the command line @rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar set CLASSPATH=
@rem Execute Gradle @rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
:end :end
@rem End local scope for the variables with windows NT shell @rem End local scope for the variables with windows NT shell

View file

@ -16,3 +16,6 @@ project(':modules').projectDir = file('modules/helma')
project(':jala').projectDir = file('modules/jala') project(':jala').projectDir = file('modules/jala')
project(':hopKit').projectDir = file('modules/jala/util/HopKit') project(':hopKit').projectDir = file('modules/jala/util/HopKit')
project(':test').projectDir = file('modules/jala/util/Test') project(':test').projectDir = file('modules/jala/util/Test')
// Rename this project to prevent redundancy and renaming of main project (VSC does not care, though)
project(':modules').name = 'modules'

21
src/dist/extras/deploy.sh vendored Executable file
View file

@ -0,0 +1,21 @@
#!/bin/sh
# Use this script as forced command of an authorized SSH key:
# command="/home/helma/extras/deploy.sh" ssh-ed25519 AAAAC3NzaC…
case "$SSH_ORIGINAL_COMMAND" in
ping)
echo pong
;;
restart)
printf 'Restarting Helma… '
sudo /bin/systemctl restart helma
printf '%s\n' 'done.'
;;
*)
# Allow any rsync command but restrict it to the installation directory
rrsync -wo /home/helma
;;
esac

View file

@ -17,7 +17,7 @@
package helma.framework; package helma.framework;
import java.io.Serializable; import java.io.Serializable;
import javax.servlet.http.Cookie; import jakarta.servlet.http.Cookie;
/** /**
* Cookie Transmitter. A simple, serializable representation * Cookie Transmitter. A simple, serializable representation

View file

@ -16,12 +16,12 @@
package helma.framework; package helma.framework;
import javax.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequest;
import java.io.Serializable; import java.io.Serializable;
import java.util.Map; import java.util.Map;
/** /**
* *
*/ */
public class RequestBean implements Serializable { public class RequestBean implements Serializable {
private static final long serialVersionUID = -6826881712426326687L; private static final long serialVersionUID = -6826881712426326687L;
@ -89,7 +89,7 @@ public class RequestBean implements Serializable {
* @return the header value, or null * @return the header value, or null
*/ */
public String getHeader(String name) { public String getHeader(String name) {
return req.getHeader(name); return req.getHeader(name);
} }
/** /**

View file

@ -19,9 +19,9 @@ package helma.framework;
import helma.util.SystemMap; import helma.util.SystemMap;
import helma.util.StringUtils; import helma.util.StringUtils;
import javax.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import jakarta.servlet.http.HttpServletResponse;
import javax.servlet.http.Cookie; import jakarta.servlet.http.Cookie;
import org.apache.commons.codec.binary.Base64; import org.apache.commons.codec.binary.Base64;

View file

@ -19,7 +19,7 @@ package helma.framework;
import helma.objectmodel.db.Transactor; import helma.objectmodel.db.Transactor;
import helma.scripting.ScriptingException; import helma.scripting.ScriptingException;
import javax.servlet.http.HttpServletResponse; import jakarta.servlet.http.HttpServletResponse;
import java.io.Serializable; import java.io.Serializable;
import java.io.StringWriter; import java.io.StringWriter;
import java.io.PrintWriter; import java.io.PrintWriter;

View file

@ -21,7 +21,7 @@ import helma.framework.core.Application;
import helma.util.*; import helma.util.*;
import helma.scripting.ScriptingException; import helma.scripting.ScriptingException;
import javax.servlet.http.HttpServletResponse; import jakarta.servlet.http.HttpServletResponse;
import java.io.*; import java.io.*;
import java.security.*; import java.security.*;
import java.util.*; import java.util.*;

View file

@ -19,11 +19,13 @@ import java.util.Vector;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.xmlrpc.XmlRpcHandler; import org.apache.xmlrpc.XmlRpcHandler;
import org.eclipse.jetty.server.handler.ContextHandler; import org.eclipse.jetty.server.handler.ContextHandler;
import org.eclipse.jetty.server.handler.ContextHandlerCollection; import org.eclipse.jetty.server.handler.ContextHandlerCollection;
import org.eclipse.jetty.server.handler.ResourceHandler; import org.eclipse.jetty.server.handler.ResourceHandler;
import org.eclipse.jetty.servlet.ServletContextHandler; import org.eclipse.jetty.ee9.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder; import org.eclipse.jetty.ee9.servlet.ServletHolder;
import org.eclipse.jetty.util.resource.ResourceFactory;
import helma.framework.core.Application; import helma.framework.core.Application;
import helma.framework.repository.FileRepository; import helma.framework.repository.FileRepository;
@ -481,23 +483,29 @@ public class ApplicationManager implements XmlRpcHandler {
// if there is a static direcory specified, mount it // if there is a static direcory specified, mount it
if (this.staticDir != null) { if (this.staticDir != null) {
String staticPath = getAbsoluteFile(this.staticDir).getCanonicalPath();
File staticContent = getAbsoluteFile(this.staticDir); getLogger().info("Serving static from " + staticPath);
getLogger().info("Serving static from " + staticContent.getPath());
getLogger().info("Mounting static at " + staticMountpoint); getLogger().info("Mounting static at " + staticMountpoint);
ResourceHandler rhandler = new ResourceHandler(); ResourceHandler rhandler = new ResourceHandler();
rhandler.setResourceBase(staticContent.getPath()); rhandler.setBaseResource(ResourceFactory.of(rhandler).newResource(staticPath));
rhandler.setWelcomeFiles(staticHome); rhandler.setWelcomeFiles(staticHome);
staticContext = ApplicationManager.this.context.addContext(staticMountpoint, ""); //$NON-NLS-1$ ContextHandler staticContext = new ContextHandler();
staticContext.setContextPath(staticMountpoint);
staticContext.setHandler(rhandler); staticContext.setHandler(rhandler);
ApplicationManager.this.context.addHandler(staticContext);
staticContext.start(); staticContext.start();
} }
appContext = new ServletContextHandler(context, pathPattern, true, true); // I hope I am correct assuming Helma does not need Jettys session management, but using
// `ServletContextHandler.SESSIONS` causes an exception: Shared scheduler not started
appContext = new ServletContextHandler(ServletContextHandler.NO_SESSIONS);
appContext.setContextPath(pathPattern);
context.addHandler(appContext);
Class servletClass = servletClassName == null ? Class servletClass = servletClassName == null ?
EmbeddedServletClient.class : Class.forName(servletClassName); EmbeddedServletClient.class : Class.forName(servletClassName);
ServletHolder holder = new ServletHolder(servletClass); ServletHolder holder = new ServletHolder(servletClass);
@ -529,10 +537,9 @@ public class ApplicationManager implements XmlRpcHandler {
} }
if (protectedStaticDir != null) { if (protectedStaticDir != null) {
File protectedContent = getAbsoluteFile(protectedStaticDir); String protectedContent = getAbsoluteFile(protectedStaticDir).getCanonicalPath();
appContext.setResourceBase(protectedContent.getPath()); appContext.setBaseResourceAsString(protectedContent);
getLogger().info("Serving protected static from " + getLogger().info("Serving protected static from " + protectedContent);
protectedContent.getPath());
} }
// Remap the context paths and start // Remap the context paths and start
@ -556,7 +563,9 @@ public class ApplicationManager implements XmlRpcHandler {
// unbind from Jetty HTTP server // unbind from Jetty HTTP server
if (ApplicationManager.this.jetty != null) { if (ApplicationManager.this.jetty != null) {
if (this.appContext != null) { if (this.appContext != null) {
ApplicationManager.this.context.removeHandler(this.appContext); // Adding appContext to the ContextHandlerCollection works (see above) but removing it causes an exception of
// incompatible types: ServletContextHandler cannot be converted to Handler
//ApplicationManager.this.context.removeHandler(this.appContext);
this.appContext.stop(); this.appContext.stop();
this.appContext.destroy(); this.appContext.destroy();
this.appContext = null; this.appContext = null;

View file

@ -16,11 +16,12 @@
package helma.main; package helma.main;
import org.eclipse.jetty.server.Connector; import org.eclipse.jetty.server.Connector;
import org.eclipse.jetty.server.HttpConfiguration; import org.eclipse.jetty.server.HttpConfiguration;
import org.eclipse.jetty.server.HttpConnectionFactory; import org.eclipse.jetty.server.HttpConnectionFactory;
import org.eclipse.jetty.server.ServerConnector; import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.util.resource.Resource;
import org.eclipse.jetty.util.resource.URLResourceFactory;
import org.eclipse.jetty.xml.XmlConfiguration; import org.eclipse.jetty.xml.XmlConfiguration;
import java.net.URL; import java.net.URL;
@ -36,18 +37,20 @@ public class JettyServer {
public static JettyServer init(Server server, ServerConfig config) throws IOException { public static JettyServer init(Server server, ServerConfig config) throws IOException {
File configFile = config.getConfigFile(); File configFile = config.getConfigFile();
if (configFile != null && configFile.exists()) { if (configFile != null && configFile.exists()) {
return new JettyServer(configFile.toURI().toURL()); URLResourceFactory resourceFactory = new URLResourceFactory();
Resource resource = resourceFactory.newResource(configFile.toURI());
return new JettyServer(resource);
} else if (config.hasWebsrvPort()) { } else if (config.hasWebsrvPort()) {
return new JettyServer(config.getWebsrvPort(), server); return new JettyServer(config.getWebsrvPort(), server);
} }
return null; return null;
} }
private JettyServer(URL url) throws IOException { private JettyServer(Resource resource) throws IOException {
http = new org.eclipse.jetty.server.Server(); http = new org.eclipse.jetty.server.Server();
try { try {
XmlConfiguration config = new XmlConfiguration(url); XmlConfiguration config = new XmlConfiguration(resource);
config.configure(http); config.configure(http);
} catch (IOException e) { } catch (IOException e) {
@ -59,7 +62,7 @@ public class JettyServer {
private JettyServer(InetSocketAddress webPort, Server server) private JettyServer(InetSocketAddress webPort, Server server)
throws IOException { throws IOException {
http = new org.eclipse.jetty.server.Server(); http = new org.eclipse.jetty.server.Server();
// start embedded web server if port is specified // start embedded web server if port is specified
@ -73,7 +76,6 @@ public class JettyServer {
connector.setHost(webPort.getAddress().getHostAddress()); connector.setHost(webPort.getAddress().getHostAddress());
connector.setPort(webPort.getPort()); connector.setPort(webPort.getPort());
connector.setIdleTimeout(30000); connector.setIdleTimeout(30000);
connector.setSoLingerTime(-1);
connector.setAcceptorPriorityDelta(0); connector.setAcceptorPriorityDelta(0);
connector.setAcceptQueueSize(0); connector.setAcceptQueueSize(0);
@ -100,12 +102,13 @@ public class JettyServer {
} }
private void openListeners() throws IOException { private void openListeners() throws IOException {
// opening the listener here allows us to run on priviledged port 80 under jsvc // opening the listener here allows us to run on privileged port 80 under jsvc
// even as non-root user, because init() is called with root privileges // even as non-root user, because init() is called with root privileges
// while start() will be called with the user we will actually run as // while start() will be called with the user we will actually run as
Connector[] connectors = http.getConnectors(); for (var connector : http.getConnectors()) {
for (int i = 0; i < connectors.length; i++) { if (connector instanceof ServerConnector) {
((ServerConnector) connectors[i]).open(); ((ServerConnector) connector).open();
}
} }
} }
} }

View file

@ -21,6 +21,7 @@ import helma.framework.repository.FileResource;
import helma.framework.core.*; import helma.framework.core.*;
import helma.objectmodel.db.DbSource; import helma.objectmodel.db.DbSource;
import helma.util.*; import helma.util.*;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
import org.apache.xmlrpc.*; import org.apache.xmlrpc.*;
@ -152,8 +153,8 @@ public class Server implements Runnable {
String javaVersion = System.getProperty("java.version", "0"); String javaVersion = System.getProperty("java.version", "0");
int majorVersion = Integer.parseInt(javaVersion.split("\\.")[0]); int majorVersion = Integer.parseInt(javaVersion.split("\\.")[0]);
if (majorVersion < 11) { if (majorVersion < 17) {
System.err.println("This version of Helma requires Java 11 or greater."); System.err.println("This version of Helma requires Java 17 or greater.");
if (majorVersion == 0) { // don't think this will ever happen, but you never know if (majorVersion == 0) { // don't think this will ever happen, but you never know
System.err.println("Your Java Runtime did not provide a version number. Please update to a more recent version."); System.err.println("Your Java Runtime did not provide a version number. Please update to a more recent version.");

View file

@ -22,18 +22,29 @@ package helma.servlet;
import helma.framework.*; import helma.framework.*;
import helma.framework.core.Application; import helma.framework.core.Application;
import helma.util.*; import helma.util.*;
import java.io.*; import java.io.*;
import java.util.*; import java.nio.charset.Charset;
import java.nio.charset.UnsupportedCharsetException;
import java.security.SecureRandom; import java.security.SecureRandom;
import java.security.NoSuchAlgorithmException; import java.security.NoSuchAlgorithmException;
import javax.servlet.*; import java.util.*;
import javax.servlet.http.*;
import jakarta.servlet.*;
import jakarta.servlet.http.*;
import org.apache.commons.codec.binary.Base64; import org.apache.commons.codec.binary.Base64;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.*; import org.apache.commons.fileupload2.core.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload; import org.apache.commons.fileupload2.core.FileItem;
import org.apache.commons.fileupload.servlet.ServletRequestContext; import org.apache.commons.fileupload2.core.FileUploadException;
import org.apache.commons.fileupload2.core.FileUploadSizeException;
import org.apache.commons.fileupload2.core.ProgressListener;
import org.apache.commons.fileupload2.jakarta.JakartaServletDiskFileUpload;
import org.apache.commons.fileupload2.jakarta.JakartaServletFileUpload;
import org.apache.commons.fileupload2.jakarta.JakartaServletRequestContext;
/** /**
* This is an abstract Hop servlet adapter. This class communicates with hop applications * This is an abstract Hop servlet adapter. This class communicates with hop applications
@ -218,9 +229,9 @@ public abstract class AbstractServletClient extends HttpServlet {
// read file uploads // read file uploads
List uploads = null; List uploads = null;
ServletRequestContext reqcx = new ServletRequestContext(request); JakartaServletRequestContext reqcx = new JakartaServletRequestContext(request);
if (ServletFileUpload.isMultipartContent(reqcx)) { if (JakartaServletFileUpload.isMultipartContent(reqcx)) {
// get session for upload progress monitoring // get session for upload progress monitoring
UploadStatus uploadStatus = getApplication().getUploadStatus(reqtrans); UploadStatus uploadStatus = getApplication().getUploadStatus(reqtrans);
try { try {
@ -228,7 +239,7 @@ public abstract class AbstractServletClient extends HttpServlet {
} catch (Exception upx) { } catch (Exception upx) {
log("Error in file upload", upx); log("Error in file upload", upx);
String message; String message;
boolean tooLarge = (upx instanceof FileUploadBase.SizeLimitExceededException); boolean tooLarge = (upx instanceof FileUploadSizeException);
if (tooLarge) { if (tooLarge) {
message = "File upload size exceeds limit of " + uploadLimit + " kB"; message = "File upload size exceeds limit of " + uploadLimit + " kB";
} else { } else {
@ -653,12 +664,12 @@ public abstract class AbstractServletClient extends HttpServlet {
map.put(name, newValues); map.put(name, newValues);
} }
protected List parseUploads(ServletRequestContext reqcx, RequestTrans reqtrans, protected List parseUploads(JakartaServletRequestContext reqcx, RequestTrans reqtrans,
final UploadStatus uploadStatus, String encoding) final UploadStatus uploadStatus, String encoding)
throws FileUploadException, UnsupportedEncodingException { throws FileUploadException, UnsupportedCharsetException, IOException {
// handle file upload // handle file upload
DiskFileItemFactory factory = new DiskFileItemFactory(); DiskFileItemFactory factory = DiskFileItemFactory.builder().get();
FileUpload upload = new FileUpload(factory); JakartaServletFileUpload upload = new JakartaServletFileUpload(factory);
// use upload limit for individual file size, but also set a limit on overall size // use upload limit for individual file size, but also set a limit on overall size
upload.setFileSizeMax(uploadLimit * 1024); upload.setFileSizeMax(uploadLimit * 1024);
upload.setSizeMax(totalUploadLimit * 1024); upload.setSizeMax(totalUploadLimit * 1024);
@ -681,7 +692,7 @@ public abstract class AbstractServletClient extends HttpServlet {
Object value; Object value;
// check if this is an ordinary HTML form element or a file upload // check if this is an ordinary HTML form element or a file upload
if (item.isFormField()) { if (item.isFormField()) {
value = item.getString(encoding); value = item.getString(Charset.forName(encoding));
} else { } else {
value = new MimePart(item); value = new MimePart(item);
} }

View file

@ -19,7 +19,7 @@ package helma.servlet;
import helma.framework.*; import helma.framework.*;
import helma.framework.core.Application; import helma.framework.core.Application;
import helma.main.*; import helma.main.*;
import javax.servlet.*; import jakarta.servlet.*;
/** /**
* Servlet client that runs a Helma application for the embedded * Servlet client that runs a Helma application for the embedded

View file

@ -23,7 +23,7 @@ import helma.main.ServerConfig;
import helma.main.Server; import helma.main.Server;
import java.io.*; import java.io.*;
import javax.servlet.*; import jakarta.servlet.*;
import java.util.*; import java.util.*;
/** /**
@ -98,7 +98,7 @@ public final class StandaloneServletClient extends AbstractServletClient {
repositoryImpl = "helma.framework.repository.FileRepository"; repositoryImpl = "helma.framework.repository.FileRepository";
} }
} }
try { try {
Repository newRepository = (Repository) Class.forName(repositoryImpl) Repository newRepository = (Repository) Class.forName(repositoryImpl)
.getConstructor(parameters) .getConstructor(parameters)
@ -116,7 +116,7 @@ public final class StandaloneServletClient extends AbstractServletClient {
} }
} }
} }
// add app dir // add app dir
FileRepository appRep = new FileRepository(appDir); FileRepository appRep = new FileRepository(appDir);
log("adding repository: " + appDir); log("adding repository: " + appDir);

View file

@ -16,7 +16,7 @@
package helma.util; package helma.util;
import org.apache.commons.fileupload.FileItem; import org.apache.commons.fileupload2.core.FileItem;
import java.io.*; import java.io.*;
import java.util.Date; import java.util.Date;
@ -238,7 +238,7 @@ public class MimePart implements Serializable {
file = new File(base, filename); file = new File(base, filename);
if (fileItem != null) { if (fileItem != null) {
fileItem.write(file); fileItem.write(file.toPath());
// null out fileItem, since calling write() may have moved the temp file // null out fileItem, since calling write() may have moved the temp file
fileItem = null; fileItem = null;
} else { } else {
@ -249,7 +249,7 @@ public class MimePart implements Serializable {
// return file name // return file name
return filename; return filename;
} catch (Exception x) { } catch (Exception x) {
System.err.println("Error in MimePart.writeToFile(): " + x); System.err.println("Error in MimePart.writeToFile(): " + x);
return null; return null;
} }
} }