Compare commits
91 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
185d5f1706 | ||
|
0552ada402 | ||
|
eda7b369a5 | ||
|
5ee5c48b1c | ||
|
2c96caadbb | ||
|
b51cc810b8 | ||
|
da7e041070 | ||
|
2680086893 | ||
|
eafc9c442c | ||
|
8c532d4caa | ||
|
bba12d9c3c | ||
|
449e4d8ae4 | ||
|
861b034ebc | ||
|
334f039e90 | ||
|
c127b4c466 | ||
|
74eb159a36 | ||
|
0514103cc1 | ||
|
46077bf5b7 | ||
|
608b58b3e0 | ||
|
5859c3b427 | ||
|
af8f7d0c33 | ||
|
d495c13e6e | ||
|
e484f532d4 | ||
|
f03bb68407 | ||
|
294b2a2418 | ||
|
45994f81bf | ||
|
4202730c11 | ||
|
09a7ce4973 | ||
|
5fa6cbc82f | ||
|
178384370f | ||
|
8d7c681ae4 | ||
|
98dfd1763a | ||
|
f6fa448ed8 | ||
|
303976279f | ||
|
be95ece466 | ||
|
4cbefc3dcc | ||
|
155250286f | ||
|
478ef3bce7 | ||
|
080cbaada9 | ||
|
6c2bae2f8a | ||
|
6ca582fcb7 | ||
|
ec7b9f9b1a | ||
|
09517cca92 | ||
|
6538be2047 | ||
|
a6e69b33eb | ||
|
f0d78a146b | ||
|
5d7c4e1a03 | ||
|
323aad1525 | ||
|
e5d11fb89a | ||
|
e6566b58bd | ||
|
ed49010303 | ||
|
f727c6dd13 | ||
|
763976abdd | ||
|
3ef176edae | ||
|
385fa1274a | ||
|
972d136665 | ||
|
329aae7fc6 | ||
|
ebece93726 | ||
|
8a9825395a | ||
|
df081c20a4 | ||
|
4137d8460e | ||
|
a627da7a1a | ||
|
a9bd29a91d | ||
|
638724925e | ||
|
1245b15e01 | ||
|
99f85c0c9b | ||
|
4a5e204e16 | ||
|
8cb5ca0daf | ||
|
afd8bbcceb | ||
|
6d90304fd7 | ||
|
f62ba44e7d | ||
|
823b506900 | ||
|
b458bfad19 | ||
|
a7a5b91933 | ||
|
20468f5bd9 | ||
|
10dd88714a | ||
|
df9c10604a | ||
|
0154160c7d | ||
|
4d65def8bb | ||
|
efd53664f2 | ||
|
345e996673 | ||
|
dcd4436fcf | ||
|
7285ce1cc8 | ||
|
a0ed47b51c | ||
|
052a7ea96f | ||
|
b8cb1e2ff0 | ||
|
cf717eff0c | ||
|
820fcca9ac | ||
|
2d011e233e | ||
|
dcc06f9afc | ||
|
4c76f0389d |
25
.editorconfig
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
charset = utf-8
|
||||||
|
end_of_line = lf
|
||||||
|
insert_final_newline = true
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 2
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
|
||||||
|
[*.java]
|
||||||
|
indent_size = 4
|
||||||
|
|
||||||
|
[*.md]
|
||||||
|
max_line_length = off
|
||||||
|
trim_trailing_whitespace = false
|
||||||
|
|
||||||
|
[*.puml]
|
||||||
|
insert_final_newline = false
|
||||||
|
|
||||||
|
[{Dockerfile,Dockerfile.*}]
|
||||||
|
indent_size = 4
|
||||||
|
|
||||||
|
[.vscode/*.json]
|
||||||
|
indent_size = 4
|
1
.gitattributes
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
* text=auto eol=lf
|
38
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
---
|
||||||
|
name: Bug report
|
||||||
|
about: Create a report to help us improve
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Describe the bug**
|
||||||
|
A clear and concise description of what the bug is.
|
||||||
|
|
||||||
|
**To Reproduce**
|
||||||
|
Steps to reproduce the behavior:
|
||||||
|
|
||||||
|
1. Go to '...'
|
||||||
|
2. Click on '....'
|
||||||
|
3. Scroll down to '....'
|
||||||
|
4. See error
|
||||||
|
|
||||||
|
**Expected behavior**
|
||||||
|
A clear and concise description of what you expected to happen.
|
||||||
|
|
||||||
|
**Screenshots**
|
||||||
|
If applicable, add screenshots to help explain your problem.
|
||||||
|
|
||||||
|
**Desktop (please complete the following information):**
|
||||||
|
|
||||||
|
- OS: [e.g. iOS]
|
||||||
|
- Browser [e.g. chrome, safari]
|
||||||
|
- Version [e.g. 22]
|
||||||
|
|
||||||
|
**Smartphone (please complete the following information):**
|
||||||
|
|
||||||
|
- Device: [e.g. iPhone6]
|
||||||
|
- OS: [e.g. iOS8.1]
|
||||||
|
- Browser [e.g. stock browser, safari]
|
||||||
|
- Version [e.g. 22]
|
||||||
|
|
||||||
|
**Additional context**
|
||||||
|
Add any other context about the problem here.
|
27
.github/ISSUE_TEMPLATE/documentation_request.md
vendored
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
---
|
||||||
|
name: Documentation request
|
||||||
|
about: Identify an area for improvement in documentation
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**What is the URL of the documentation?**
|
||||||
|
|
||||||
|
- **Example:** https://github.com/evantill/docker-cheerpj/blob/main/README.md#example-of-using-cheerpj-on-your-computer
|
||||||
|
|
||||||
|
- *Note:* This URL includes the web page and the section of the documentation.
|
||||||
|
|
||||||
|
**What can be improved?**
|
||||||
|
|
||||||
|
A clear and concise description of what can be improved.
|
||||||
|
Examples:
|
||||||
|
|
||||||
|
- "I don't understand where the ${XYZ} variable is set."
|
||||||
|
- "There seems to be a step missing between 'X' and 'Z'. I don't know how to get to 'Z'."
|
||||||
|
- "When I run `command sub-command ...` I get the following error:"
|
||||||
|
- "I don't know what is meant by 'gerble barb gazoink` in the instructions".
|
||||||
|
|
||||||
|
**Additional context**
|
||||||
|
|
||||||
|
Add any other context or screenshots to help describe the documentation improvement.
|
||||||
|
If you think the documentation improvement is operating system specific,
|
||||||
|
please indicate which operating system is being used.
|
17
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
---
|
||||||
|
name: Feature request
|
||||||
|
about: Suggest an idea for this project
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Is your feature request related to a problem? Please describe.**
|
||||||
|
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||||
|
|
||||||
|
**Describe the solution you'd like**
|
||||||
|
A clear and concise description of what you want to happen.
|
||||||
|
|
||||||
|
**Describe alternatives you've considered**
|
||||||
|
A clear and concise description of any alternative solutions or features you've considered.
|
||||||
|
|
||||||
|
**Additional context**
|
||||||
|
Add any other context or screenshots about the feature request here.
|
26
.github/workflows/main.yml
vendored
@ -9,11 +9,11 @@ jobs:
|
|||||||
build-jdk11:
|
build-jdk11:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
||||||
- uses: actions/setup-java@v2
|
- uses: actions/setup-java@v3
|
||||||
with:
|
with:
|
||||||
distribution: "zulu"
|
distribution: "zulu"
|
||||||
java-version: 11
|
java-version: 11
|
||||||
@ -22,7 +22,7 @@ jobs:
|
|||||||
|
|
||||||
- name: get tag name
|
- name: get tag name
|
||||||
id: version
|
id: version
|
||||||
run: echo ::set-output name=VERSION::${GITHUB_REF#refs/*/}
|
run: echo "VERSION=${GITHUB_REF#refs/*/}" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
- name: build with maven
|
- name: build with maven
|
||||||
run: mvn --batch-mode --define java.net.useSystemProxies=true package
|
run: mvn --batch-mode --define java.net.useSystemProxies=true package
|
||||||
@ -37,7 +37,7 @@ jobs:
|
|||||||
run: cp target/plantuml.war target/plantuml-jsp-${{ steps.version.outputs.VERSION }}.war
|
run: cp target/plantuml.war target/plantuml-jsp-${{ steps.version.outputs.VERSION }}.war
|
||||||
|
|
||||||
- name: temporarily save generated war files
|
- name: temporarily save generated war files
|
||||||
uses: actions/upload-artifact@v2
|
uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: war-jre11
|
name: war-jre11
|
||||||
path: target/plantuml*-${{ steps.version.outputs.VERSION }}.war
|
path: target/plantuml*-${{ steps.version.outputs.VERSION }}.war
|
||||||
@ -45,11 +45,11 @@ jobs:
|
|||||||
build-jdk8:
|
build-jdk8:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
||||||
- uses: actions/setup-java@v2
|
- uses: actions/setup-java@v3
|
||||||
with:
|
with:
|
||||||
distribution: "zulu"
|
distribution: "zulu"
|
||||||
java-version: 8
|
java-version: 8
|
||||||
@ -58,7 +58,7 @@ jobs:
|
|||||||
|
|
||||||
- name: get tag name
|
- name: get tag name
|
||||||
id: version
|
id: version
|
||||||
run: echo ::set-output name=VERSION::${GITHUB_REF#refs/*/}
|
run: echo "VERSION=${GITHUB_REF#refs/*/}" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
- name: Remove test code (not java 8 compatible)
|
- name: Remove test code (not java 8 compatible)
|
||||||
run: rm -rf src/test
|
run: rm -rf src/test
|
||||||
@ -76,7 +76,7 @@ jobs:
|
|||||||
run: cp target/plantuml.war target/plantuml-jre8-jsp-${{ steps.version.outputs.VERSION }}.war
|
run: cp target/plantuml.war target/plantuml-jre8-jsp-${{ steps.version.outputs.VERSION }}.war
|
||||||
|
|
||||||
- name: temporarily save generated war files
|
- name: temporarily save generated war files
|
||||||
uses: actions/upload-artifact@v2
|
uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: war-jre8
|
name: war-jre8
|
||||||
path: target/plantuml*-${{ steps.version.outputs.VERSION }}.war
|
path: target/plantuml*-${{ steps.version.outputs.VERSION }}.war
|
||||||
@ -88,13 +88,13 @@ jobs:
|
|||||||
- build-jdk8
|
- build-jdk8
|
||||||
steps:
|
steps:
|
||||||
- name: retrieve generated war files (jre8)
|
- name: retrieve generated war files (jre8)
|
||||||
uses: actions/download-artifact@v2
|
uses: actions/download-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: war-jre8
|
name: war-jre8
|
||||||
path: artifacts
|
path: artifacts
|
||||||
|
|
||||||
- name: retrieve generated war files (jre11)
|
- name: retrieve generated war files (jre11)
|
||||||
uses: actions/download-artifact@v2
|
uses: actions/download-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: war-jre11
|
name: war-jre11
|
||||||
path: artifacts
|
path: artifacts
|
||||||
@ -116,7 +116,7 @@ jobs:
|
|||||||
needs:
|
needs:
|
||||||
- publish-releases
|
- publish-releases
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
||||||
@ -186,11 +186,11 @@ jobs:
|
|||||||
needs:
|
needs:
|
||||||
- publish-releases
|
- publish-releases
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
||||||
- uses: actions/setup-java@v2
|
- uses: actions/setup-java@v3
|
||||||
with:
|
with:
|
||||||
distribution: "zulu"
|
distribution: "zulu"
|
||||||
java-version: 11
|
java-version: 11
|
||||||
|
48
.github/workflows/tests.yml
vendored
@ -8,11 +8,11 @@ jobs:
|
|||||||
test-java-8-war-generation:
|
test-java-8-war-generation:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
||||||
- uses: actions/setup-java@v2
|
- uses: actions/setup-java@v3
|
||||||
with:
|
with:
|
||||||
distribution: "zulu"
|
distribution: "zulu"
|
||||||
java-version: 8
|
java-version: 8
|
||||||
@ -29,7 +29,7 @@ jobs:
|
|||||||
run: mvn --batch-mode -f pom.jdk8.xml -D java.net.useSystemProxies=true clean package
|
run: mvn --batch-mode -f pom.jdk8.xml -D java.net.useSystemProxies=true clean package
|
||||||
|
|
||||||
- name: temporarily save generated files
|
- name: temporarily save generated files
|
||||||
uses: actions/upload-artifact@v2
|
uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: war-jre8
|
name: war-jre8
|
||||||
path: target/plantuml.war
|
path: target/plantuml.war
|
||||||
@ -42,17 +42,17 @@ jobs:
|
|||||||
matrix:
|
matrix:
|
||||||
java-version: [ 11, 17 ]
|
java-version: [ 11, 17 ]
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
||||||
- name: retrieve generated files (jre8)
|
- name: retrieve generated files (jre8)
|
||||||
uses: actions/download-artifact@v2
|
uses: actions/download-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: war-jre8
|
name: war-jre8
|
||||||
path: artifacts
|
path: artifacts
|
||||||
|
|
||||||
- uses: actions/setup-java@v2
|
- uses: actions/setup-java@v3
|
||||||
with:
|
with:
|
||||||
distribution: "zulu"
|
distribution: "zulu"
|
||||||
java-version: ${{ matrix.java-version }}
|
java-version: ${{ matrix.java-version }}
|
||||||
@ -69,7 +69,7 @@ jobs:
|
|||||||
run: sleep 5s
|
run: sleep 5s
|
||||||
|
|
||||||
- name: Run tests against "mvn jetty:run" server
|
- name: Run tests against "mvn jetty:run" server
|
||||||
run: mvn --batch-mode test -DskipTests=false -DargLine="-Dsystem.test.server=http://localhost:8080/plantuml"
|
run: mvn --batch-mode test -DskipTests=false -Dgroups=\!graphviz-test -DargLine="-Dsystem.test.server=http://localhost:8080/plantuml"
|
||||||
|
|
||||||
test-mvn-livecycle:
|
test-mvn-livecycle:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
@ -77,11 +77,11 @@ jobs:
|
|||||||
matrix:
|
matrix:
|
||||||
java-version: [ 11, 17 ]
|
java-version: [ 11, 17 ]
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
||||||
- uses: actions/setup-java@v2
|
- uses: actions/setup-java@v3
|
||||||
with:
|
with:
|
||||||
distribution: "zulu"
|
distribution: "zulu"
|
||||||
java-version: ${{ matrix.java-version }}
|
java-version: ${{ matrix.java-version }}
|
||||||
@ -119,11 +119,11 @@ jobs:
|
|||||||
matrix:
|
matrix:
|
||||||
java-version: [ 11, 17 ]
|
java-version: [ 11, 17 ]
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
||||||
- uses: actions/setup-java@v2
|
- uses: actions/setup-java@v3
|
||||||
with:
|
with:
|
||||||
distribution: "zulu"
|
distribution: "zulu"
|
||||||
java-version: ${{ matrix.java-version }}
|
java-version: ${{ matrix.java-version }}
|
||||||
@ -131,7 +131,7 @@ jobs:
|
|||||||
cache: "maven"
|
cache: "maven"
|
||||||
|
|
||||||
- name: Run tests against jetty embedded server
|
- name: Run tests against jetty embedded server
|
||||||
run: mvn --batch-mode clean test -DskipTests=false
|
run: mvn --batch-mode clean test -DskipTests=false -Dgroups=\!graphviz-test
|
||||||
|
|
||||||
test-mvn-jetty-run:
|
test-mvn-jetty-run:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
@ -140,11 +140,11 @@ jobs:
|
|||||||
matrix:
|
matrix:
|
||||||
java-version: [ 11, 17 ]
|
java-version: [ 11, 17 ]
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
||||||
- uses: actions/setup-java@v2
|
- uses: actions/setup-java@v3
|
||||||
with:
|
with:
|
||||||
distribution: "zulu"
|
distribution: "zulu"
|
||||||
java-version: ${{ matrix.java-version }}
|
java-version: ${{ matrix.java-version }}
|
||||||
@ -161,7 +161,7 @@ jobs:
|
|||||||
run: sleep 20s
|
run: sleep 20s
|
||||||
|
|
||||||
- name: Run tests against "mvn jetty:run" server
|
- name: Run tests against "mvn jetty:run" server
|
||||||
run: mvn --batch-mode test -DskipTests=false -DargLine="-Dsystem.test.server=http://localhost:8080/plantuml"
|
run: mvn --batch-mode test -DskipTests=false -Dgroups=\!graphviz-test -DargLine="-Dsystem.test.server=http://localhost:8080/plantuml"
|
||||||
|
|
||||||
test-jetty-runner:
|
test-jetty-runner:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
@ -170,11 +170,11 @@ jobs:
|
|||||||
matrix:
|
matrix:
|
||||||
java-version: [ 11, 17 ]
|
java-version: [ 11, 17 ]
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
||||||
- uses: actions/setup-java@v2
|
- uses: actions/setup-java@v3
|
||||||
with:
|
with:
|
||||||
distribution: "zulu"
|
distribution: "zulu"
|
||||||
java-version: ${{ matrix.java-version }}
|
java-version: ${{ matrix.java-version }}
|
||||||
@ -191,7 +191,7 @@ jobs:
|
|||||||
run: sleep 5s
|
run: sleep 5s
|
||||||
|
|
||||||
- name: Run tests against "mvn jetty:run" server
|
- name: Run tests against "mvn jetty:run" server
|
||||||
run: mvn --batch-mode test -DskipTests=false -DargLine="-Dsystem.test.server=http://localhost:8080/plantuml"
|
run: mvn --batch-mode test -DskipTests=false -Dgroups=\!graphviz-test -DargLine="-Dsystem.test.server=http://localhost:8080/plantuml"
|
||||||
|
|
||||||
test-jetty:
|
test-jetty:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
@ -200,11 +200,11 @@ jobs:
|
|||||||
matrix:
|
matrix:
|
||||||
java-version: [ 11, 17 ]
|
java-version: [ 11, 17 ]
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
||||||
- uses: actions/setup-java@v2
|
- uses: actions/setup-java@v3
|
||||||
with:
|
with:
|
||||||
distribution: "zulu"
|
distribution: "zulu"
|
||||||
java-version: ${{ matrix.java-version }}
|
java-version: ${{ matrix.java-version }}
|
||||||
@ -217,7 +217,7 @@ jobs:
|
|||||||
- name: Build the jetty docker stack
|
- name: Build the jetty docker stack
|
||||||
run: |
|
run: |
|
||||||
docker image build -f Dockerfile.jetty -t plantuml-server:local .
|
docker image build -f Dockerfile.jetty -t plantuml-server:local .
|
||||||
docker run -d -p 8080:8080 -e BASE_URL=plantuml plantuml-server:local
|
docker run -d --hostname=test.localhost -p 8080:8080 -e BASE_URL=plantuml plantuml-server:local
|
||||||
|
|
||||||
- name: Check running containers
|
- name: Check running containers
|
||||||
run: docker ps
|
run: docker ps
|
||||||
@ -232,11 +232,11 @@ jobs:
|
|||||||
matrix:
|
matrix:
|
||||||
java-version: [ 11, 17 ]
|
java-version: [ 11, 17 ]
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
||||||
- uses: actions/setup-java@v2
|
- uses: actions/setup-java@v3
|
||||||
with:
|
with:
|
||||||
distribution: "zulu"
|
distribution: "zulu"
|
||||||
java-version: ${{ matrix.java-version }}
|
java-version: ${{ matrix.java-version }}
|
||||||
@ -249,7 +249,7 @@ jobs:
|
|||||||
- name: Build the tomcat docker stack
|
- name: Build the tomcat docker stack
|
||||||
run: |
|
run: |
|
||||||
docker image build -f Dockerfile.tomcat -t plantuml-server:local .
|
docker image build -f Dockerfile.tomcat -t plantuml-server:local .
|
||||||
docker run -d -p 8080:8080 -e BASE_URL=plantuml plantuml-server:local
|
docker run -d --hostname=test.localhost -p 8080:8080 -e BASE_URL=plantuml plantuml-server:local
|
||||||
|
|
||||||
- name: Check running containers
|
- name: Check running containers
|
||||||
run: docker ps
|
run: docker ps
|
||||||
|
8
.gitignore
vendored
@ -1,5 +1,13 @@
|
|||||||
|
# Eclipse Ignores
|
||||||
target
|
target
|
||||||
.settings
|
.settings
|
||||||
.classpath
|
.classpath
|
||||||
.project
|
.project
|
||||||
.checkstyle
|
.checkstyle
|
||||||
|
|
||||||
|
# IntelliJ ignores
|
||||||
|
.idea/
|
||||||
|
out/
|
||||||
|
*.iml
|
||||||
|
*.ipr
|
||||||
|
*.iws
|
16
.vscode/settings.json
vendored
@ -2,21 +2,29 @@
|
|||||||
"java.configuration.updateBuildConfiguration": "automatic",
|
"java.configuration.updateBuildConfiguration": "automatic",
|
||||||
"cSpell.words": [
|
"cSpell.words": [
|
||||||
"Arnaud",
|
"Arnaud",
|
||||||
|
"buildx",
|
||||||
"ditaa",
|
"ditaa",
|
||||||
"endditaa",
|
"endditaa",
|
||||||
"enduml",
|
"enduml",
|
||||||
"epstext",
|
"epstext",
|
||||||
"etag",
|
"etag",
|
||||||
|
"ghaction",
|
||||||
|
"inmemory",
|
||||||
"Lalloni",
|
"Lalloni",
|
||||||
|
"monaco",
|
||||||
"plantuml",
|
"plantuml",
|
||||||
|
"puml",
|
||||||
"Roques",
|
"Roques",
|
||||||
"servlet",
|
"servlet",
|
||||||
"servlets",
|
"servlets",
|
||||||
"startditaa",
|
"startditaa",
|
||||||
"startuml",
|
"startuml",
|
||||||
"utxt",
|
"undock",
|
||||||
"ghaction",
|
"utxt"
|
||||||
"buildx"
|
|
||||||
],
|
],
|
||||||
"cSpell.allowCompoundWords": true
|
"cSpell.allowCompoundWords": true,
|
||||||
|
"svg.preview.background": "dark-transparent",
|
||||||
|
"files.associations": {
|
||||||
|
"*.jspf": "html"
|
||||||
|
}
|
||||||
}
|
}
|
@ -1,6 +1,6 @@
|
|||||||
FROM maven:3-jdk-11-slim AS builder
|
FROM maven:3-eclipse-temurin-17 AS builder
|
||||||
|
|
||||||
COPY pom.xml /app/
|
COPY pom.xml pom.parent.xml /app/
|
||||||
COPY src/main /app/src/main/
|
COPY src/main /app/src/main/
|
||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
@ -8,7 +8,7 @@ RUN mvn --batch-mode --define java.net.useSystemProxies=true package
|
|||||||
|
|
||||||
########################################################################################
|
########################################################################################
|
||||||
|
|
||||||
FROM jetty:11.0.7-jre11-slim
|
FROM jetty:11.0.18-jre17-eclipse-temurin
|
||||||
|
|
||||||
# Proxy and OldProxy need empty path segments support in URIs
|
# Proxy and OldProxy need empty path segments support in URIs
|
||||||
# Hence: allow AMBIGUOUS_EMPTY_SEGMENT
|
# Hence: allow AMBIGUOUS_EMPTY_SEGMENT
|
||||||
@ -16,23 +16,64 @@ FROM jetty:11.0.7-jre11-slim
|
|||||||
RUN sed -i 's/# jetty\.httpConfig\.uriCompliance=DEFAULT/jetty.httpConfig.uriCompliance=DEFAULT,AMBIGUOUS_EMPTY_SEGMENT/g' /var/lib/jetty/start.d/server.ini
|
RUN sed -i 's/# jetty\.httpConfig\.uriCompliance=DEFAULT/jetty.httpConfig.uriCompliance=DEFAULT,AMBIGUOUS_EMPTY_SEGMENT/g' /var/lib/jetty/start.d/server.ini
|
||||||
|
|
||||||
USER root
|
USER root
|
||||||
|
|
||||||
RUN apt-get update && \
|
RUN apt-get update && \
|
||||||
apt-get install -y --no-install-recommends \
|
apt-get install -y --no-install-recommends \
|
||||||
|
curl \
|
||||||
fonts-noto-cjk \
|
fonts-noto-cjk \
|
||||||
graphviz \
|
libgd3 \
|
||||||
&& \
|
&& \
|
||||||
rm -rf /var/lib/apt/lists/* && \
|
rm -rf /var/lib/apt/lists/* && \
|
||||||
/generate-jetty-start.sh
|
/generate-jetty-start.sh
|
||||||
|
|
||||||
COPY docker-entrypoint.sh /entrypoint.sh
|
# Build Graphviz from source because there are no binary distributions for recent versions
|
||||||
|
ARG GRAPHVIZ_VERSION
|
||||||
|
ARG GRAPHVIZ_BUILD_DIR=/tmp/graphiz-build
|
||||||
|
RUN apt-get update && \
|
||||||
|
apt-get install -y --no-install-recommends \
|
||||||
|
build-essential \
|
||||||
|
jq \
|
||||||
|
libexpat1-dev \
|
||||||
|
libgd-dev \
|
||||||
|
zlib1g-dev \
|
||||||
|
&& \
|
||||||
|
mkdir -p $GRAPHVIZ_BUILD_DIR && \
|
||||||
|
cd $GRAPHVIZ_BUILD_DIR && \
|
||||||
|
GRAPHVIZ_VERSION=${GRAPHVIZ_VERSION:-$(curl -s https://gitlab.com/api/v4/projects/4207231/releases/ | jq -r '.[] | .name' | sort -V -r | head -1)} && \
|
||||||
|
curl -o graphviz.tar.gz https://gitlab.com/api/v4/projects/4207231/packages/generic/graphviz-releases/${GRAPHVIZ_VERSION}/graphviz-${GRAPHVIZ_VERSION}.tar.gz && \
|
||||||
|
tar -xzf graphviz.tar.gz && \
|
||||||
|
cd graphviz-$GRAPHVIZ_VERSION && \
|
||||||
|
./configure && \
|
||||||
|
make && \
|
||||||
|
make install && \
|
||||||
|
apt-get remove -y \
|
||||||
|
build-essential \
|
||||||
|
jq \
|
||||||
|
libexpat1-dev \
|
||||||
|
libgd-dev \
|
||||||
|
zlib1g-dev \
|
||||||
|
&& \
|
||||||
|
apt-get autoremove -y && \
|
||||||
|
apt-get clean && \
|
||||||
|
rm -rf /var/lib/apt/lists/* && \
|
||||||
|
rm -rf $GRAPHVIZ_BUILD_DIR
|
||||||
|
|
||||||
|
COPY docker-entrypoint.jetty.sh /entrypoint.sh
|
||||||
RUN chmod +x /entrypoint.sh
|
RUN chmod +x /entrypoint.sh
|
||||||
|
|
||||||
USER jetty
|
USER jetty
|
||||||
|
|
||||||
ENV BASE_URL=ROOT \
|
ENV WEBAPP_PATH=$JETTY_BASE/webapps
|
||||||
WEBAPP_PATH=$JETTY_BASE/webapps
|
|
||||||
RUN rm -rf $WEBAPP_PATH && \
|
RUN rm -rf $WEBAPP_PATH && \
|
||||||
mkdir -p $WEBAPP_PATH
|
mkdir -p $WEBAPP_PATH
|
||||||
COPY --from=builder /app/target/plantuml.war $WEBAPP_PATH/ROOT.war
|
COPY --from=builder /app/target/plantuml.war /plantuml.war
|
||||||
|
COPY ROOT.jetty.xml $WEBAPP_PATH/ROOT.xml
|
||||||
|
|
||||||
|
# Openshift https://docs.openshift.com/container-platform/4.9/openshift_images/create-images.html#images-create-guide-openshift_create-images
|
||||||
|
USER root
|
||||||
|
RUN chgrp -R 0 $JETTY_BASE && chmod -R g=u $JETTY_BASE
|
||||||
|
RUN chgrp -R 0 /tmp && chmod -R g=u /tmp
|
||||||
|
USER jetty
|
||||||
|
|
||||||
ENTRYPOINT ["/entrypoint.sh"]
|
ENTRYPOINT ["/entrypoint.sh"]
|
||||||
|
VOLUME ["/tmp/jetty"]
|
||||||
|
76
Dockerfile.jetty-alpine
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
FROM maven:3-eclipse-temurin-17-alpine AS builder
|
||||||
|
|
||||||
|
COPY pom.xml pom.parent.xml /app/
|
||||||
|
COPY src/main /app/src/main/
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
RUN mvn --batch-mode --define java.net.useSystemProxies=true package
|
||||||
|
|
||||||
|
########################################################################################
|
||||||
|
|
||||||
|
FROM jetty:11.0.18-jre17-alpine-eclipse-temurin
|
||||||
|
|
||||||
|
# Proxy and OldProxy need empty path segments support in URIs
|
||||||
|
# Hence: allow AMBIGUOUS_EMPTY_SEGMENT
|
||||||
|
# Changes are only active if `/generate-jetty-start.sh` is called!
|
||||||
|
RUN sed -i 's/# jetty\.httpConfig\.uriCompliance=DEFAULT/jetty.httpConfig.uriCompliance=DEFAULT,AMBIGUOUS_EMPTY_SEGMENT/g' /var/lib/jetty/start.d/server.ini
|
||||||
|
|
||||||
|
USER root
|
||||||
|
|
||||||
|
RUN apk add --no-cache \
|
||||||
|
curl \
|
||||||
|
font-noto-cjk \
|
||||||
|
libgd \
|
||||||
|
&& \
|
||||||
|
/generate-jetty-start.sh
|
||||||
|
|
||||||
|
#RUN apk add --no-cache graphviz
|
||||||
|
ARG GRAPHVIZ_VERSION
|
||||||
|
ARG GRAPHVIZ_BUILD_DIR=/tmp/graphiz-build
|
||||||
|
RUN apk add --no-cache \
|
||||||
|
g++ \
|
||||||
|
jq \
|
||||||
|
expat-dev \
|
||||||
|
make \
|
||||||
|
zlib \
|
||||||
|
pkgconf \
|
||||||
|
&& \
|
||||||
|
mkdir -p $GRAPHVIZ_BUILD_DIR && \
|
||||||
|
cd $GRAPHVIZ_BUILD_DIR && \
|
||||||
|
GRAPHVIZ_VERSION=${GRAPHVIZ_VERSION:-$(curl -s https://gitlab.com/api/v4/projects/4207231/releases/ | jq -r '.[] | .name' | sort -V -r | head -1)} && \
|
||||||
|
curl -o graphviz.tar.gz https://gitlab.com/api/v4/projects/4207231/packages/generic/graphviz-releases/${GRAPHVIZ_VERSION}/graphviz-${GRAPHVIZ_VERSION}.tar.gz && \
|
||||||
|
tar -xzf graphviz.tar.gz && \
|
||||||
|
cd graphviz-$GRAPHVIZ_VERSION && \
|
||||||
|
./configure && \
|
||||||
|
make && \
|
||||||
|
make install && \
|
||||||
|
apk del --no-cache \
|
||||||
|
g++ \
|
||||||
|
jq \
|
||||||
|
expat-dev \
|
||||||
|
make \
|
||||||
|
zlib \
|
||||||
|
&& \
|
||||||
|
rm -rf $GRAPHVIZ_BUILD_DIR
|
||||||
|
|
||||||
|
COPY docker-entrypoint.jetty.sh /entrypoint.sh
|
||||||
|
RUN chmod +x /entrypoint.sh
|
||||||
|
|
||||||
|
USER jetty
|
||||||
|
|
||||||
|
ENV WEBAPP_PATH=$JETTY_BASE/webapps
|
||||||
|
RUN rm -rf $WEBAPP_PATH && \
|
||||||
|
mkdir -p $WEBAPP_PATH
|
||||||
|
COPY --from=builder /app/target/plantuml.war /plantuml.war
|
||||||
|
COPY ROOT.jetty.xml $WEBAPP_PATH/ROOT.xml
|
||||||
|
|
||||||
|
# Openshift https://docs.openshift.com/container-platform/4.9/openshift_images/create-images.html#images-create-guide-openshift_create-images
|
||||||
|
USER root
|
||||||
|
RUN chgrp -R 0 $JETTY_BASE && \
|
||||||
|
chmod -R g=u $JETTY_BASE
|
||||||
|
RUN chgrp -R 0 /tmp && \
|
||||||
|
chmod -R g=u /tmp
|
||||||
|
USER jetty
|
||||||
|
|
||||||
|
ENTRYPOINT ["/entrypoint.sh"]
|
||||||
|
VOLUME ["/tmp/jetty"]
|
@ -1,6 +1,6 @@
|
|||||||
FROM maven:3-jdk-11-slim AS builder
|
FROM maven:3-eclipse-temurin-11 AS builder
|
||||||
|
|
||||||
COPY pom.xml /app/
|
COPY pom.xml pom.parent.xml /app/
|
||||||
COPY src/main /app/src/main/
|
COPY src/main /app/src/main/
|
||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
@ -8,23 +8,58 @@ RUN mvn --batch-mode --define java.net.useSystemProxies=true -Dapache-jsp.scope=
|
|||||||
|
|
||||||
########################################################################################
|
########################################################################################
|
||||||
|
|
||||||
FROM tomcat:10-jdk11-openjdk-slim
|
FROM tomcat:10-jdk11
|
||||||
|
|
||||||
RUN apt-get update && \
|
RUN apt-get update && \
|
||||||
apt-get install -y --no-install-recommends \
|
apt-get install -y --no-install-recommends \
|
||||||
|
curl \
|
||||||
fonts-noto-cjk \
|
fonts-noto-cjk \
|
||||||
graphviz \
|
libgd3 \
|
||||||
&& \
|
&& \
|
||||||
rm -rf /var/lib/apt/lists/*
|
rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
COPY docker-entrypoint.sh /entrypoint.sh
|
# Build Graphviz from source because there are no binary distributions for recent versions
|
||||||
|
ARG GRAPHVIZ_VERSION
|
||||||
|
ARG GRAPHVIZ_BUILD_DIR=/tmp/graphiz-build
|
||||||
|
RUN apt-get update && \
|
||||||
|
apt-get install -y --no-install-recommends \
|
||||||
|
build-essential \
|
||||||
|
jq \
|
||||||
|
libexpat1-dev \
|
||||||
|
libgd-dev \
|
||||||
|
zlib1g-dev \
|
||||||
|
&& \
|
||||||
|
mkdir -p $GRAPHVIZ_BUILD_DIR && \
|
||||||
|
cd $GRAPHVIZ_BUILD_DIR && \
|
||||||
|
GRAPHVIZ_VERSION=${GRAPHVIZ_VERSION:-$(curl -s https://gitlab.com/api/v4/projects/4207231/releases/ | jq -r '.[] | .name' | sort -V -r | head -1)} && \
|
||||||
|
curl -o graphviz.tar.gz https://gitlab.com/api/v4/projects/4207231/packages/generic/graphviz-releases/${GRAPHVIZ_VERSION}/graphviz-${GRAPHVIZ_VERSION}.tar.gz && \
|
||||||
|
tar -xzf graphviz.tar.gz && \
|
||||||
|
cd graphviz-$GRAPHVIZ_VERSION && \
|
||||||
|
./configure && \
|
||||||
|
make && \
|
||||||
|
make install && \
|
||||||
|
apt-get remove -y \
|
||||||
|
build-essential \
|
||||||
|
jq \
|
||||||
|
libexpat1-dev \
|
||||||
|
libgd-dev \
|
||||||
|
zlib1g-dev \
|
||||||
|
&& \
|
||||||
|
apt-get autoremove -y && \
|
||||||
|
apt-get clean && \
|
||||||
|
rm -rf /var/lib/apt/lists/* && \
|
||||||
|
rm -rf $GRAPHVIZ_BUILD_DIR
|
||||||
|
|
||||||
|
COPY docker-entrypoint.tomcat.sh /entrypoint.sh
|
||||||
RUN chmod +x /entrypoint.sh
|
RUN chmod +x /entrypoint.sh
|
||||||
|
|
||||||
ENV BASE_URL=ROOT \
|
ENV WEBAPP_PATH=$CATALINA_HOME/webapps
|
||||||
WEBAPP_PATH=$CATALINA_HOME/webapps
|
|
||||||
RUN rm -rf $WEBAPP_PATH && \
|
RUN rm -rf $WEBAPP_PATH && \
|
||||||
mkdir -p $WEBAPP_PATH
|
mkdir -p $WEBAPP_PATH
|
||||||
COPY --from=builder /app/target/plantuml.war $WEBAPP_PATH/ROOT.war
|
COPY --from=builder /app/target/plantuml.war /plantuml.war
|
||||||
|
|
||||||
|
# Openshift https://docs.openshift.com/container-platform/4.9/openshift_images/create-images.html#images-create-guide-openshift_create-images
|
||||||
|
RUN chgrp -R 0 $CATALINA_HOME && chmod -R g=u $CATALINA_HOME
|
||||||
|
|
||||||
ENTRYPOINT ["/entrypoint.sh"]
|
ENTRYPOINT ["/entrypoint.sh"]
|
||||||
CMD ["catalina.sh", "run"]
|
CMD ["catalina.sh", "run"]
|
||||||
|
39
README.md
@ -16,10 +16,21 @@
|
|||||||
|
|
||||||
PlantUML Server is a web application to generate UML diagrams on-the-fly.
|
PlantUML Server is a web application to generate UML diagrams on-the-fly.
|
||||||
|
|
||||||
[PlantUML is **not** affected by the log4j vulnerability.](https://github.com/plantuml/plantuml/issues/826)
|
> [PlantUML is **not** affected by the log4j vulnerability.](https://github.com/plantuml/plantuml/issues/826)
|
||||||
|
|
||||||
|
> **Breaking changes**:
|
||||||
|
> The PlantUML core removed the deprecated `ALLOW_PLANTUML_INCLUDE` environment property feature and switch to the
|
||||||
|
> `PLANTUML_SECURITY_PROFILE` concept with version `v1.2023.9`.
|
||||||
|
> All details about PlantUML's security can be found on <https://plantuml.com/security>.
|
||||||
|
>
|
||||||
|
> By default PlantUML server sets the `PLANTUML_SECURITY_PROFILE` to `INTERNET`.
|
||||||
|
> If you need more access to e.g. other ports than 80 (http) and 443 (https) or even access to local files, please
|
||||||
|
> consider using one of the allowlist features.
|
||||||
|
> It is strongly advised **not** to set the `PLANTUML_SECURITY_PROFILE` below `INTERNET`!
|
||||||
|
|
||||||
![PlantUML Server](https://raw.githubusercontent.com/plantuml/plantuml-server/master/screenshots/screenshot.png)
|
![PlantUML Server](https://raw.githubusercontent.com/plantuml/plantuml-server/master/docs/screenshot.png)
|
||||||
|
|
||||||
|
More examples and features about the Web UI can be found in [docs/WebUI](https://github.com/plantuml/plantuml-server/tree/master/docs/WebUI).
|
||||||
|
|
||||||
To know more about PlantUML, please visit https://plantuml.com.
|
To know more about PlantUML, please visit https://plantuml.com.
|
||||||
|
|
||||||
@ -115,6 +126,22 @@ You can set all the following variables:
|
|||||||
* `BASE_URL`
|
* `BASE_URL`
|
||||||
* PlantUML Base URL path
|
* PlantUML Base URL path
|
||||||
* Default value: `ROOT`
|
* Default value: `ROOT`
|
||||||
|
* `PLANTUML_SECURITY_PROFILE`
|
||||||
|
* Set PlantUML security profile. See [PlantUML security](https://plantuml.com/security).
|
||||||
|
* If you need more access to e.g. other ports than 80 (http) and 443 (https) or even access to local files, please consider using one of the allowlist features:
|
||||||
|
* `plantuml.allowlist.path`
|
||||||
|
* `plantuml.include.path`
|
||||||
|
* `plantuml.allowlist.url`
|
||||||
|
* It is strongly advised **not** to set the `PLANTUML_SECURITY_PROFILE` below `INTERNET`!
|
||||||
|
* Default value: `INTERNET`
|
||||||
|
* `PLANTUML_PROPERTY_FILE`
|
||||||
|
* Set PlantUML system properties (like over the Java command line using the `-Dpropertyname=value` syntax).
|
||||||
|
* To see what kind of file content is supported, see the documentation of [`java.util.Properties.load`](https://docs.oracle.com/javase/8/docs/api/java/util/Properties.html#load-java.io.Reader-).
|
||||||
|
* Default value: `null`
|
||||||
|
* `PLANTUML_CONFIG_FILE`
|
||||||
|
* Local path to a PlantUML configuration file (identical to the `-config` flag on the CLI)
|
||||||
|
* File content will be added before each PlantUML diagram code.
|
||||||
|
* Default value: `null`
|
||||||
* `PLANTUML_LIMIT_SIZE`
|
* `PLANTUML_LIMIT_SIZE`
|
||||||
* Limits image width and height
|
* Limits image width and height
|
||||||
* Default value: `4096`
|
* Default value: `4096`
|
||||||
@ -124,9 +151,9 @@ You can set all the following variables:
|
|||||||
* `HTTP_AUTHORIZATION`
|
* `HTTP_AUTHORIZATION`
|
||||||
* when calling the `proxy` endpoint, the value of `HTTP_AUTHORIZATION` will be used to set the HTTP Authorization header
|
* when calling the `proxy` endpoint, the value of `HTTP_AUTHORIZATION` will be used to set the HTTP Authorization header
|
||||||
* Default value: `null`
|
* Default value: `null`
|
||||||
* `ALLOW_PLANTUML_INCLUDE`
|
* `HTTP_PROXY_READ_TIMEOUT`
|
||||||
* Enables `!include` processing which can read files from the server into diagrams. Files are read relative to the current working directory.
|
* when calling the `proxy` endpoint, the value of `HTTP_PROXY_READ_TIMEOUT` will be the connection read timeout in milliseconds
|
||||||
* Default value: `false`
|
* Default value: `10000` (10 seconds)
|
||||||
|
|
||||||
|
|
||||||
## Alternate: How to build your docker image
|
## Alternate: How to build your docker image
|
||||||
@ -166,4 +193,4 @@ mvn package -f pom.jdk8.xml [-Dapache-jsp.scope=compile]
|
|||||||
|
|
||||||
It is possible to use PlantUML with a reverse proxy.
|
It is possible to use PlantUML with a reverse proxy.
|
||||||
|
|
||||||
You can find this and other examples [here](./examples).
|
You can find this and other examples [here](https://github.com/plantuml/plantuml-server/tree/master/examples).
|
||||||
|
9
ROOT.jetty.xml
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "https://www.eclipse.org/jetty/configure_10_0.dtd">
|
||||||
|
|
||||||
|
<Configure class="org.eclipse.jetty.webapp.WebAppContext">
|
||||||
|
<Set name="contextPath">
|
||||||
|
<Env name="CONTEXT_PATH" />
|
||||||
|
</Set>
|
||||||
|
<Set name="war">/plantuml.war</Set>
|
||||||
|
</Configure>
|
@ -1,11 +1,9 @@
|
|||||||
version: '3.3'
|
|
||||||
|
|
||||||
services:
|
services:
|
||||||
plantuml-server:
|
plantuml-server:
|
||||||
build:
|
build:
|
||||||
context: .
|
context: .
|
||||||
dockerfile: Dockerfile.jetty
|
dockerfile: Dockerfile.jetty
|
||||||
image: plantuml/plantuml-server:jetty-local
|
image: plantuml/plantuml-server:jetty
|
||||||
container_name: plantuml-server
|
container_name: plantuml-server
|
||||||
ports:
|
ports:
|
||||||
- 8080:8080
|
- 8080:8080
|
||||||
|
@ -3,11 +3,8 @@
|
|||||||
# cspell:enableCompoundWords
|
# cspell:enableCompoundWords
|
||||||
###########################################################
|
###########################################################
|
||||||
|
|
||||||
# use environment variables
|
# ensure context path starts with a slash
|
||||||
if [ "$BASE_URL" != "ROOT" ]; then
|
export CONTEXT_PATH="/${BASE_URL#'/'}"
|
||||||
mkdir -p "$(dirname "$WEBAPP_PATH/$BASE_URL")"
|
|
||||||
mv "$WEBAPP_PATH/ROOT.war" "$WEBAPP_PATH/$BASE_URL.war"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# base image entrypoint
|
# base image entrypoint
|
||||||
if [ -x /docker-entrypoint.sh ]; then
|
if [ -x /docker-entrypoint.sh ]; then
|
18
docker-entrypoint.tomcat.sh
Executable file
@ -0,0 +1,18 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# cspell:words mkdir
|
||||||
|
# cspell:enableCompoundWords
|
||||||
|
###########################################################
|
||||||
|
|
||||||
|
# choose war file name so that context path is correctly set based on BASE_URL,
|
||||||
|
# following the rules from https://tomcat.apache.org/tomcat-9.0-doc/config/context.html#Naming,
|
||||||
|
# specifically remove leading and trailing slashes and replace the remaining ones by hashes.
|
||||||
|
export FILE_NAME="$(echo "$BASE_URL" | sed -e 's:^/::' -e 's:/$::' -e 's:/:#:g')"
|
||||||
|
export FILE_PATH="$WEBAPP_PATH/$FILE_NAME.war"
|
||||||
|
mv /plantuml.war "$FILE_PATH"
|
||||||
|
|
||||||
|
# base image entrypoint
|
||||||
|
if [ -x /docker-entrypoint.sh ]; then
|
||||||
|
/docker-entrypoint.sh "$@"
|
||||||
|
else
|
||||||
|
exec "$@"
|
||||||
|
fi
|
25
docs/WebUI/README.md
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
# PlantUML Server Web UI
|
||||||
|
|
||||||
|
## First example: "Alice and Bob"
|
||||||
|
|
||||||
|
![alice-bob](https://raw.githubusercontent.com/plantuml/plantuml-server/master/docs/WebUI/gifs/alice-bob.gif)
|
||||||
|
|
||||||
|
## Multipaging
|
||||||
|
|
||||||
|
Just see what you want.
|
||||||
|
And if its the second diagram page, so be it.
|
||||||
|
|
||||||
|
![multipaging](https://raw.githubusercontent.com/plantuml/plantuml-server/master/docs/WebUI/gifs/multipaging.gif)
|
||||||
|
|
||||||
|
## Split Screen
|
||||||
|
|
||||||
|
You have multiple monitors? You want to share your Window but only show the diagram and not the code? Than do it!
|
||||||
|
|
||||||
|
![multipaging](https://raw.githubusercontent.com/plantuml/plantuml-server/master/docs/WebUI/gifs/split-screen.gif)
|
||||||
|
|
||||||
|
## More
|
||||||
|
|
||||||
|
- [Settings](https://github.com/plantuml/plantuml-server/blob/master/docs/WebUI/settings.md)
|
||||||
|
- [PlantUML Language Features](https://github.com/plantuml/plantuml-server/blob/master/docs/WebUI/language-features.md)
|
||||||
|
- [Import/Export](https://github.com/plantuml/plantuml-server/blob/master/docs/WebUI/import-export.md)
|
||||||
|
- [Mobile Version](https://github.com/plantuml/plantuml-server/blob/master/docs/WebUI/mobile.md)
|
BIN
docs/WebUI/gifs/alice-bob.gif
Normal file
After Width: | Height: | Size: 83 KiB |
BIN
docs/WebUI/gifs/auto-completion-emojis.gif
Normal file
After Width: | Height: | Size: 142 KiB |
BIN
docs/WebUI/gifs/auto-completion-icons.gif
Normal file
After Width: | Height: | Size: 116 KiB |
BIN
docs/WebUI/gifs/auto-completion-themes+icons.gif
Normal file
After Width: | Height: | Size: 272 KiB |
BIN
docs/WebUI/gifs/auto-completion-themes.gif
Normal file
After Width: | Height: | Size: 129 KiB |
BIN
docs/WebUI/gifs/diagram-export.gif
Normal file
After Width: | Height: | Size: 296 KiB |
BIN
docs/WebUI/gifs/diagram-import.gif
Normal file
After Width: | Height: | Size: 1.5 MiB |
BIN
docs/WebUI/gifs/mobile-alice-bob.gif
Normal file
After Width: | Height: | Size: 110 KiB |
BIN
docs/WebUI/gifs/mobile-settings.gif
Normal file
After Width: | Height: | Size: 253 KiB |
BIN
docs/WebUI/gifs/multipaging.gif
Normal file
After Width: | Height: | Size: 259 KiB |
BIN
docs/WebUI/gifs/settings-rendering-type.gif
Normal file
After Width: | Height: | Size: 575 KiB |
BIN
docs/WebUI/gifs/settings-theme.gif
Normal file
After Width: | Height: | Size: 460 KiB |
BIN
docs/WebUI/gifs/split-screen.gif
Normal file
After Width: | Height: | Size: 211 KiB |
BIN
docs/WebUI/gifs/validation-start-end.gif
Normal file
After Width: | Height: | Size: 255 KiB |
21
docs/WebUI/import-export.md
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
# Import and Export editable PlantUML Diagrams
|
||||||
|
|
||||||
|
Similar to [draw.io](https://app.diagrams.net) it is possible to load and continue editing PlantUML diagram images.
|
||||||
|
|
||||||
|
|
||||||
|
## Export a diagram
|
||||||
|
|
||||||
|
Via the editor menu or <kbd>Ctrl</kbd> + <kbd>S</kbd> (or <kbd>Meta</kbd> + <kbd>S</kbd> in the case of a Mac) you can open the file save dialog.
|
||||||
|
Here you can edit the file name, choose a file/diagram type and download the diagram.
|
||||||
|
The default is to download the PlantUML code.
|
||||||
|
|
||||||
|
![export](https://raw.githubusercontent.com/plantuml/plantuml-server/master/docs/WebUI/gifs/diagram-export.gif)
|
||||||
|
|
||||||
|
|
||||||
|
## Import a diagram
|
||||||
|
|
||||||
|
This feature is based on the PlantUML meta data which currently **support only PNG and SVG** diagrams.
|
||||||
|
Besides a diagram image, you can of course also load a diagram code file.
|
||||||
|
Moreover, because it is so nice and convenient, we also added a drag-and-drop feature.
|
||||||
|
|
||||||
|
![import](https://raw.githubusercontent.com/plantuml/plantuml-server/master/docs/WebUI/gifs/diagram-import.gif)
|
41
docs/WebUI/language-features.md
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
# PlantUML Language Features
|
||||||
|
|
||||||
|
## Auto Completion
|
||||||
|
|
||||||
|
### Icons
|
||||||
|
|
||||||
|
- type `<&` to get a list of PlantUML available icons
|
||||||
|
- see a preview of the suggested icon in its description
|
||||||
|
- [PlantUML documentation](https://plantuml.com/openiconic)
|
||||||
|
|
||||||
|
![icons](https://raw.githubusercontent.com/plantuml/plantuml-server/master/docs/WebUI/gifs/auto-completion-icons.gif)
|
||||||
|
|
||||||
|
### Emojis
|
||||||
|
|
||||||
|
- type `<:` to get a list of PlantUML available icons
|
||||||
|
- see a preview of the suggested icon in its description
|
||||||
|
- [PlantUML documentation](https://plantuml.com/creole#68305e25f5788db0)
|
||||||
|
|
||||||
|
![emojis](https://raw.githubusercontent.com/plantuml/plantuml-server/master/docs/WebUI/gifs/auto-completion-emojis.gif)
|
||||||
|
|
||||||
|
### Themes
|
||||||
|
|
||||||
|
- type `!t` to get the suggestion `theme`
|
||||||
|
- type `!theme ` to get a list of (local) available PlantUML themes.
|
||||||
|
- [PlantUML documentation](https://plantuml.com/theme)
|
||||||
|
|
||||||
|
![themes](https://raw.githubusercontent.com/plantuml/plantuml-server/master/docs/WebUI/gifs/auto-completion-themes.gif)
|
||||||
|
|
||||||
|
|
||||||
|
## Validation
|
||||||
|
|
||||||
|
### `@start...` and `@end...`
|
||||||
|
|
||||||
|
- `@start...` should always be the first command
|
||||||
|
- `@end...` should alway be the last command
|
||||||
|
- `@start...` should only exists once
|
||||||
|
- `@end...` should only exists once
|
||||||
|
- `@end...` should have the same type as `@start...`
|
||||||
|
e.g.: `@startjson ... @endjson`
|
||||||
|
|
||||||
|
![start-end](https://raw.githubusercontent.com/plantuml/plantuml-server/master/docs/WebUI/gifs/validation-start-end.gif)
|
12
docs/WebUI/mobile.md
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
# Mobile Version
|
||||||
|
|
||||||
|
PlantUML Server is mobile ready.
|
||||||
|
|
||||||
|
## First example: "Alice and Bob"
|
||||||
|
|
||||||
|
![alice-bob](https://raw.githubusercontent.com/plantuml/plantuml-server/master/docs/WebUI/gifs/mobile-alice-bob.gif)
|
||||||
|
|
||||||
|
|
||||||
|
## Settings
|
||||||
|
|
||||||
|
![settings](https://raw.githubusercontent.com/plantuml/plantuml-server/master/docs/WebUI/gifs/mobile-settings.gif)
|
38
docs/WebUI/settings.md
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
# Settings
|
||||||
|
|
||||||
|
Via the menu or <kbd>Ctrl</kbd> + <kbd>,</kbd> (or <kbd>Meta</kbd> + <kbd>,</kbd> in the case of a Mac) you can open the Setting dialog.
|
||||||
|
|
||||||
|
## Theme
|
||||||
|
|
||||||
|
_The sun is too bright? You live on the dark side or only in the basement?_
|
||||||
|
Choose between the `dark` and `light` theme.
|
||||||
|
|
||||||
|
![theme](https://raw.githubusercontent.com/plantuml/plantuml-server/master/docs/WebUI/gifs/settings-theme.gif)
|
||||||
|
|
||||||
|
## Rendering Type
|
||||||
|
|
||||||
|
You want always to work and see only the SVG version? Not Problem.
|
||||||
|
Choose the rendering type you want to see.
|
||||||
|
|
||||||
|
![rendering-type](https://raw.githubusercontent.com/plantuml/plantuml-server/master/docs/WebUI/gifs/settings-rendering-type.gif)
|
||||||
|
|
||||||
|
## Editor Watcher Timeout
|
||||||
|
|
||||||
|
You can change the Editor Watcher Timeout, by default it is `500 ms`.
|
||||||
|
|
||||||
|
|
||||||
|
## Editor Options
|
||||||
|
|
||||||
|
You can change the options of the editor:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
{
|
||||||
|
automaticLayout: true,
|
||||||
|
fixedOverflowWidgets: true,
|
||||||
|
minimap: { enabled: false },
|
||||||
|
scrollbar: { alwaysConsumeMouseWheel: false },
|
||||||
|
scrollBeyondLastLine: false,
|
||||||
|
tabSize: 2,
|
||||||
|
theme: "vs", // "vs-dark"
|
||||||
|
}
|
||||||
|
```
|
83
docs/contribution/front-end.md
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
# Front-end Contribution
|
||||||
|
|
||||||
|
## Web UI
|
||||||
|
|
||||||
|
The Web UI uses vanilla javascript.
|
||||||
|
|
||||||
|
As online editor Microsoft's [Monaco Editor](https://github.com/microsoft/monaco-editor).
|
||||||
|
The documentation can be found [here](https://microsoft.github.io/monaco-editor/docs.html).
|
||||||
|
You may recognize the editor since it's the code editor from [VS Code](https://github.com/microsoft/vscode).
|
||||||
|
|
||||||
|
The main entry file are `index.jsp`, `previewer.jsp` and `error.jsp`.
|
||||||
|
|
||||||
|
The code structure is mainly divided into `components` and `js`:
|
||||||
|
- `components` are for example a modal or dialog.
|
||||||
|
Anything that include things directly seen and rendered on the page.
|
||||||
|
- `js` contains more the things that do not have a direct influence on the UI. For example the PlantUML language features or the methods for cross-browser/cross-tab communication.
|
||||||
|
|
||||||
|
|
||||||
|
## PlantUML Language Features
|
||||||
|
|
||||||
|
At the moment there is no defined PlantUML language.
|
||||||
|
Feel free to create one!
|
||||||
|
But until then the syntax highlighting form `apex` is used.
|
||||||
|
IMHO it works quite well.
|
||||||
|
|
||||||
|
All PlantUML language features are bundled into a seperate file `plantuml-language.min.js`.
|
||||||
|
Therefore anything under `js/language` should be independent!
|
||||||
|
|
||||||
|
### Code Completion
|
||||||
|
What do you need to do to create a new code completion feature:
|
||||||
|
1. create a new JS file under `js/language/completion` - let's say `xxx.js`
|
||||||
|
2. create a new `registerXxxCompletion` method
|
||||||
|
_It may help you if you look into the [documentation](https://microsoft.github.io/monaco-editor/docs.html#functions/languages.registerCompletionItemProvider.html) or at the provided [sample code](https://microsoft.github.io/monaco-editor/playground.html?source=v0.38.0#example-extending-language-services-completion-provider-example) to understand more about `monaco.languages.registerCompletionItemProvider`._
|
||||||
|
```js
|
||||||
|
PlantUmlLanguageFeatures.prototype.registerEmojiCompletion = function() {
|
||||||
|
monaco.languages.registerCompletionItemProvider(PlantUmlLanguageFeatures.languageSelector, {
|
||||||
|
provideCompletionItems: async (model, position) => {
|
||||||
|
// ...
|
||||||
|
return { suggestions };
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
```
|
||||||
|
4. add your new method inside the language initialization inside `js/language/language.js`
|
||||||
|
```diff
|
||||||
|
const PlantUmlLanguageFeatures = function(initialize = true) {
|
||||||
|
if (initialize) {
|
||||||
|
// initialize all validation and code completion methods
|
||||||
|
this.addStartEndValidationListeners();
|
||||||
|
this.registerThemeCompletion();
|
||||||
|
this.registerIconCompletion();
|
||||||
|
this.registerEmojiCompletion();
|
||||||
|
+ this.registerXxxCompletion();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
### Code Validation
|
||||||
|
What do you need to do to create a new code validation feature:
|
||||||
|
1. create a new JS file under `js/language/validation/listeners` - let's say `zzz-validation.js`
|
||||||
|
2. register your validation methods to the designated event listener
|
||||||
|
The validation event order is: `before` → `code` → `line` → `after`
|
||||||
|
You may look at `js/language/validation/listeners/start-end-validation.js` to get an idea how to register a new listener.
|
||||||
|
3. add your new method inside the language initialization inside `js/language/language.js`
|
||||||
|
```diff
|
||||||
|
const PlantUmlLanguageFeatures = function(initialize = true) {
|
||||||
|
if (initialize) {
|
||||||
|
// initialize all validation and code completion methods
|
||||||
|
this.addStartEndValidationListeners();
|
||||||
|
+ this.addZzzValidationListeners();
|
||||||
|
this.registerThemeCompletion();
|
||||||
|
this.registerIconCompletion();
|
||||||
|
this.registerEmojiCompletion();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### Tipps
|
||||||
|
|
||||||
|
- `pom.xml`: set `withoutCSSJSCompress` to `true` to deactivate the minification
|
||||||
|
- use `mvn fizzed-watcher:run` to watch changes and automatically update the bundled `plantuml.min.{css,js}` and `plantuml-language.min.js` files
|
||||||
|
- if the browser get the error `ReferenceError: require is not defined` or something similar related to the webjars, try `mvn clean install` to get things straight
|
BIN
docs/screenshot.png
Normal file
After Width: | Height: | Size: 48 KiB |
@ -1,4 +1,6 @@
|
|||||||
# Examples
|
# Examples
|
||||||
|
|
||||||
|
- [Additional fonts inside the PlantUML docker container](./additional-fonts)
|
||||||
- [Nginx simple reverse proxy example](./nginx-simple)
|
- [Nginx simple reverse proxy example](./nginx-simple)
|
||||||
- [Nginx reverse proxy example with defined location directive (different context path)](./nginx-contextpath)
|
- [Nginx reverse proxy example with defined location directive (different context path)](./nginx-contextpath)
|
||||||
|
- [Kubernetes simple deployment](./kubernetes-simple)
|
||||||
|
73
examples/additional-fonts/README.md
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
# Additional fonts inside the PlantUML docker container
|
||||||
|
|
||||||
|
It is possible to make additional fonts available to PlantUML by mapping them via a volume within the docker container.
|
||||||
|
|
||||||
|
Since the base image from the docker container is using Ubuntu, fonts can easily be provided by just adding them somewhere inside the `~/.local/share/fonts` directory.
|
||||||
|
|
||||||
|
**Tipp**: to not overwrite the container fonts add the additional files inside an own sub-folder, e.g., `custom` or `host`.
|
||||||
|
|
||||||
|
In the following you can find an example how to provide all fonts of your host machine in the PlantUML docker container for Jetty and Tomcat.
|
||||||
|
|
||||||
|
|
||||||
|
## Jetty
|
||||||
|
|
||||||
|
In the case of the Jetty docker container the home directory is `/var/lib/jetty`.
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
services:
|
||||||
|
plantuml-server:
|
||||||
|
image: plantuml/plantuml-server:jetty
|
||||||
|
container_name: plantuml-server
|
||||||
|
ports:
|
||||||
|
- "80:8080"
|
||||||
|
environment:
|
||||||
|
- TZ=Europe/Berlin
|
||||||
|
- BASE_URL=plantuml
|
||||||
|
volumes:
|
||||||
|
- /usr/share/fonts:/var/lib/jetty/.local/share/fonts/host:ro
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## Tomcat
|
||||||
|
|
||||||
|
In the case of the Tomcat docker container the home directory is `/root`.
|
||||||
|
_Yes, the tomcat container is running as `root` which is basically a really bad idea w.r.t. security. Create a pull request and maintain it if you want to change that._
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
services:
|
||||||
|
plantuml-server:
|
||||||
|
image: plantuml/plantuml-server:tomcat
|
||||||
|
container_name: plantuml-server
|
||||||
|
ports:
|
||||||
|
- "80:8080"
|
||||||
|
environment:
|
||||||
|
- TZ=Europe/Berlin
|
||||||
|
- BASE_URL=plantuml
|
||||||
|
volumes:
|
||||||
|
- /usr/share/fonts:/root/.local/share/fonts/host:ro
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## Verification
|
||||||
|
|
||||||
|
The following command will print a list of all available fonts inside the docker container:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker exec -it plantuml-server fc-list
|
||||||
|
```
|
||||||
|
|
||||||
|
To find a special font add a grep filter to the command:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker exec -it plantuml-server fc-list | grep "<name-of-font>"
|
||||||
|
```
|
||||||
|
|
||||||
|
Naturally, it is also possible to check this via PlantUML itself by rendering the following diagram:
|
||||||
|
|
||||||
|
```plantuml
|
||||||
|
@startuml
|
||||||
|
listfonts
|
||||||
|
@enduml
|
||||||
|
```
|
||||||
|
|
||||||
|
**Note**: If you have added a lot of fonts: (a) this diagram may take a few seconds to generate, and (b) eventually the PNG image may be clipped. To avoid the latter, render the diagram as an SVG image.
|
13
examples/additional-fonts/docker-compose.yml
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
version: "3"
|
||||||
|
|
||||||
|
services:
|
||||||
|
plantuml-server:
|
||||||
|
image: plantuml/plantuml-server:jetty
|
||||||
|
container_name: plantuml-server
|
||||||
|
ports:
|
||||||
|
- "80:8080"
|
||||||
|
environment:
|
||||||
|
- TZ=Europe/Berlin
|
||||||
|
- BASE_URL=plantuml
|
||||||
|
volumes:
|
||||||
|
- /usr/share/fonts:/var/lib/jetty/.local/share/fonts/host:ro
|
51
examples/kubernetes-simple/README.md
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
# PlantUML Kubernetes Deployment
|
||||||
|
|
||||||
|
In this example, PlantUML is deployed on an Kubernetes cluster using a `Deployment`, a `Service` and an `Ingress`.
|
||||||
|
|
||||||
|
## Quick start
|
||||||
|
|
||||||
|
Install:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Hint: Adjust the Ingress host to your URL
|
||||||
|
|
||||||
|
kubectl create ns plantuml
|
||||||
|
kubectl -n plantuml apply -f deployment.yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
Uninstall:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
kubectl -n plantuml delete -f deployment.yaml
|
||||||
|
kubectl delete ns plantuml
|
||||||
|
```
|
||||||
|
|
||||||
|
## TLS configuration
|
||||||
|
|
||||||
|
Create a TLS `Secret` and extend the `Ingress` spec with a TLS configuration:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
[...]
|
||||||
|
tls:
|
||||||
|
- hosts:
|
||||||
|
- plantuml-example.localhost
|
||||||
|
secretName: plantuml-tls
|
||||||
|
```
|
||||||
|
|
||||||
|
Since the `Ingress Controller` terminates the TLS and routes `http` to the application, we might need to tell the application explicitly that it got a forwarded request.
|
||||||
|
|
||||||
|
This configuration changes depending on the `Ingress Controller`. Here an nginx example:
|
||||||
|
|
||||||
|
```
|
||||||
|
annotations:
|
||||||
|
kubernetes.io/ingress.class: nginx
|
||||||
|
nginx.ingress.kubernetes.io/configuration-snippet: |
|
||||||
|
more_set_headers "X-Forwarded-Proto: https";
|
||||||
|
```
|
||||||
|
|
||||||
|
## Useful commands
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# see whats going on inside your Deployment
|
||||||
|
kubectl -n plantuml logs -l "app.kubernetes.io/name=plantuml"
|
||||||
|
```
|
84
examples/kubernetes-simple/deployment.yaml
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
---
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: plantuml
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: plantuml
|
||||||
|
app.kubernetes.io/instance: plantuml
|
||||||
|
spec:
|
||||||
|
replicas: 3 # Can be adjusted
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app.kubernetes.io/name: plantuml
|
||||||
|
app.kubernetes.io/instance: plantuml
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: plantuml
|
||||||
|
app.kubernetes.io/instance: plantuml
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: plantuml
|
||||||
|
securityContext:
|
||||||
|
allowPrivilegeEscalation: false
|
||||||
|
image: plantuml/plantuml-server:jetty-v1.2022.6
|
||||||
|
imagePullPolicy: Always
|
||||||
|
# env: # In case of different base URL
|
||||||
|
# - name: BASE_URL
|
||||||
|
# value: plantuml
|
||||||
|
ports:
|
||||||
|
- name: http
|
||||||
|
containerPort: 8080
|
||||||
|
protocol: TCP
|
||||||
|
livenessProbe:
|
||||||
|
tcpSocket:
|
||||||
|
port: http
|
||||||
|
readinessProbe:
|
||||||
|
tcpSocket:
|
||||||
|
port: http
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
cpu: 500m
|
||||||
|
memory: 2048Mi
|
||||||
|
requests:
|
||||||
|
cpu: 250m
|
||||||
|
memory: 1024Mi
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: plantuml
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: plantuml
|
||||||
|
app.kubernetes.io/instance: plantuml
|
||||||
|
spec:
|
||||||
|
type: ClusterIP
|
||||||
|
ports:
|
||||||
|
- port: 80
|
||||||
|
targetPort: http
|
||||||
|
protocol: TCP
|
||||||
|
name: http
|
||||||
|
selector:
|
||||||
|
app.kubernetes.io/name: plantuml
|
||||||
|
app.kubernetes.io/instance: plantuml
|
||||||
|
---
|
||||||
|
apiVersion: networking.k8s.io/v1
|
||||||
|
kind: Ingress
|
||||||
|
metadata:
|
||||||
|
name: plantuml
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: plantuml
|
||||||
|
app.kubernetes.io/instance: plantuml
|
||||||
|
spec:
|
||||||
|
rules:
|
||||||
|
- host: plantuml-example.localhost
|
||||||
|
http:
|
||||||
|
paths:
|
||||||
|
- backend:
|
||||||
|
service:
|
||||||
|
name: plantuml
|
||||||
|
port:
|
||||||
|
number: 80
|
||||||
|
path: /
|
||||||
|
pathType: Prefix
|
@ -41,10 +41,6 @@ YEAH! You are now using PlantUML behind a simple Nginx reverse proxy.
|
|||||||
|
|
||||||
# PlantUML
|
# PlantUML
|
||||||
location /plantuml/ {
|
location /plantuml/ {
|
||||||
proxy_set_header HOST $host;
|
|
||||||
proxy_set_header X-Forwarded-Host $host;
|
|
||||||
proxy_set_header X-Forwarded-Proto $scheme;
|
|
||||||
|
|
||||||
proxy_pass http://plantuml-server:8080/plantuml/;
|
proxy_pass http://plantuml-server:8080/plantuml/;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -52,12 +48,31 @@ location /plantuml/ {
|
|||||||
```
|
```
|
||||||
|
|
||||||
- `location /plantuml/` to reverse only the context path `/plantuml`
|
- `location /plantuml/` to reverse only the context path `/plantuml`
|
||||||
- `proxy_set_header HOST $host` and `proxy_set_header X-Forwarded-Host $host` to replaces local plantuml server ip with FQDN
|
|
||||||
- `proxy_set_header X-Forwarded-Proto $scheme` to use reverse proxy protocol schema instead of communication schema between reverse proxy and plantuml server
|
|
||||||
- `proxy_pass http://plantuml-server:8080/plantuml/` to set reverse proxy path to plantuml server.
|
- `proxy_pass http://plantuml-server:8080/plantuml/` to set reverse proxy path to plantuml server.
|
||||||
Use the docker container name `plantuml-server` instead of ip addresses.
|
Use the docker container name `plantuml-server` instead of ip addresses.
|
||||||
Also, use the same context path (`BASE_URL`) as PlantUML, which is configurable as an environment variable in the docker-compose file.
|
Also, use the same context path (`BASE_URL`) as PlantUML, which is configurable as an environment variable in the docker-compose file.
|
||||||
|
|
||||||
|
NOTE: `BASE_URL`, `location` and therefore the `proxy_pass` should have the some context path!
|
||||||
|
If that is not possible it may be possible to solve the problem by using NGINX `sub_filter`:
|
||||||
|
```nginx
|
||||||
|
# PlantUML
|
||||||
|
location /plantuml/ {
|
||||||
|
sub_filter '<base href="/" />' '<base href="/plantuml/" />';
|
||||||
|
sub_filter_types text/html;
|
||||||
|
|
||||||
|
proxy_pass http://plantuml-server:8080/;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
NOTE: Since [PR#256](https://github.com/plantuml/plantuml-server/pull/256) it is possible to use deep base URLs.
|
||||||
|
So with e.g. `BASE_URL=foo/bar` the following is possible:
|
||||||
|
```nginx
|
||||||
|
# PlantUML
|
||||||
|
location /foo/bar/ {
|
||||||
|
proxy_pass http://plantuml-server:8080/foo/bar/;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
## Nginx and PlantUML server
|
## Nginx and PlantUML server
|
||||||
|
|
||||||
@ -69,8 +84,8 @@ services:
|
|||||||
image: plantuml/plantuml-server:jetty
|
image: plantuml/plantuml-server:jetty
|
||||||
container_name: plantuml-server
|
container_name: plantuml-server
|
||||||
environment:
|
environment:
|
||||||
- TZ="Europe/Berlin"
|
- TZ=Europe/Berlin
|
||||||
- BASE_URL="plantuml"
|
- BASE_URL=plantuml
|
||||||
|
|
||||||
nginx:
|
nginx:
|
||||||
image: nginx:alpine
|
image: nginx:alpine
|
||||||
@ -78,7 +93,7 @@ services:
|
|||||||
ports:
|
ports:
|
||||||
- "80:80"
|
- "80:80"
|
||||||
environment:
|
environment:
|
||||||
- TZ="Europe/Berlin"
|
- TZ=Europe/Berlin
|
||||||
volumes:
|
volumes:
|
||||||
- ./nginx.conf:/etc/nginx/nginx.conf:ro
|
- ./nginx.conf:/etc/nginx/nginx.conf:ro
|
||||||
```
|
```
|
||||||
|
@ -5,7 +5,7 @@ services:
|
|||||||
image: plantuml/plantuml-server:jetty
|
image: plantuml/plantuml-server:jetty
|
||||||
container_name: plantuml-server
|
container_name: plantuml-server
|
||||||
environment:
|
environment:
|
||||||
- TZ="Europe/Berlin"
|
- TZ=Europe/Berlin
|
||||||
- BASE_URL=plantuml
|
- BASE_URL=plantuml
|
||||||
|
|
||||||
nginx:
|
nginx:
|
||||||
@ -14,6 +14,6 @@ services:
|
|||||||
ports:
|
ports:
|
||||||
- "80:80"
|
- "80:80"
|
||||||
environment:
|
environment:
|
||||||
- TZ="Europe/Berlin"
|
- TZ=Europe/Berlin
|
||||||
volumes:
|
volumes:
|
||||||
- ./nginx.conf:/etc/nginx/nginx.conf:ro
|
- ./nginx.conf:/etc/nginx/nginx.conf:ro
|
||||||
|
@ -18,10 +18,6 @@ http {
|
|||||||
|
|
||||||
# PlantUML
|
# PlantUML
|
||||||
location /plantuml/ {
|
location /plantuml/ {
|
||||||
proxy_set_header HOST $host;
|
|
||||||
proxy_set_header X-Forwarded-Host $host;
|
|
||||||
proxy_set_header X-Forwarded-Proto $scheme;
|
|
||||||
|
|
||||||
proxy_pass http://plantuml-server:8080/plantuml/;
|
proxy_pass http://plantuml-server:8080/plantuml/;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -64,7 +64,7 @@ services:
|
|||||||
image: plantuml/plantuml-server:jetty
|
image: plantuml/plantuml-server:jetty
|
||||||
container_name: plantuml-server
|
container_name: plantuml-server
|
||||||
environment:
|
environment:
|
||||||
- TZ="Europe/Berlin"
|
- TZ=Europe/Berlin
|
||||||
|
|
||||||
nginx:
|
nginx:
|
||||||
image: nginx:alpine
|
image: nginx:alpine
|
||||||
@ -72,7 +72,7 @@ services:
|
|||||||
ports:
|
ports:
|
||||||
- "80:80"
|
- "80:80"
|
||||||
environment:
|
environment:
|
||||||
- TZ="Europe/Berlin"
|
- TZ=Europe/Berlin
|
||||||
volumes:
|
volumes:
|
||||||
- ./nginx.conf:/etc/nginx/nginx.conf:ro
|
- ./nginx.conf:/etc/nginx/nginx.conf:ro
|
||||||
```
|
```
|
||||||
|
@ -5,7 +5,7 @@ services:
|
|||||||
image: plantuml/plantuml-server:jetty
|
image: plantuml/plantuml-server:jetty
|
||||||
container_name: plantuml-server
|
container_name: plantuml-server
|
||||||
environment:
|
environment:
|
||||||
- TZ="Europe/Berlin"
|
- TZ=Europe/Berlin
|
||||||
|
|
||||||
nginx:
|
nginx:
|
||||||
image: nginx:alpine
|
image: nginx:alpine
|
||||||
@ -13,6 +13,6 @@ services:
|
|||||||
ports:
|
ports:
|
||||||
- "80:80"
|
- "80:80"
|
||||||
environment:
|
environment:
|
||||||
- TZ="Europe/Berlin"
|
- TZ=Europe/Berlin
|
||||||
volumes:
|
volumes:
|
||||||
- ./nginx.conf:/etc/nginx/nginx.conf:ro
|
- ./nginx.conf:/etc/nginx/nginx.conf:ro
|
||||||
|
434
pom.jdk8.xml
@ -6,109 +6,30 @@
|
|||||||
>
|
>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<parent>
|
||||||
<groupId>org.sourceforge.plantuml</groupId>
|
<groupId>org.sourceforge.plantuml</groupId>
|
||||||
<artifactId>plantumlservlet</artifactId>
|
<artifactId>plantumlservlet-parent</artifactId>
|
||||||
<version>1-SNAPSHOT</version>
|
<version>1-SNAPSHOT</version>
|
||||||
|
<relativePath>pom.parent.xml</relativePath>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<artifactId>plantumlservlet</artifactId>
|
||||||
<packaging>war</packaging>
|
<packaging>war</packaging>
|
||||||
|
|
||||||
<name>PlantUML Servlet</name>
|
|
||||||
<url>https://plantuml.github.io/plantuml-server/index.html</url>
|
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<java.version>8</java.version>
|
<java.version>8</java.version>
|
||||||
<maven.compiler.source>${java.version}</maven.compiler.source>
|
|
||||||
<maven.compiler.target>${java.version}</maven.compiler.target>
|
|
||||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
|
||||||
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
|
||||||
|
|
||||||
<!--
|
|
||||||
Skip tests by default.
|
|
||||||
Run tests manually:
|
|
||||||
- mvn test -DskipTests=false
|
|
||||||
- mvn test -DskipTests=false -DargLine="-Dsystem.test.server=http://localhost:8080/plantuml"
|
|
||||||
-->
|
|
||||||
<skipTests>true</skipTests>
|
|
||||||
|
|
||||||
<!--
|
|
||||||
This artifact is required for:
|
|
||||||
1. EmbeddedJettyServer -> scope: test
|
|
||||||
2. Tomcat docker image -> scope: compile
|
|
||||||
BUT: Jetty docker image as well as jetty-runner will crash on runtime if
|
|
||||||
this artifact is included because it's already provided so that the
|
|
||||||
artifact would apear multiple times on the classpath.
|
|
||||||
You can test it via: `mvn jetty:run [-Dapache-jsp.scope=compile]`
|
|
||||||
Error: java.util.ServiceConfigurationError: org.apache.juli.logging.Log: org.eclipse.jetty.apache.jsp.JuliLog not a subtype
|
|
||||||
HENCE: Default is the "test" scope and for Tomcat docker image building add:
|
|
||||||
-Dapache-jsp.scope=compile
|
|
||||||
-->
|
|
||||||
<apache-jsp.scope>test</apache-jsp.scope>
|
|
||||||
|
|
||||||
<maven.build.timestamp.format>yyyyMMdd-HHmm</maven.build.timestamp.format>
|
|
||||||
<timestamp>${maven.build.timestamp}</timestamp>
|
|
||||||
|
|
||||||
<wtp.version>1.5</wtp.version>
|
|
||||||
<wtp.contextName>plantuml</wtp.contextName>
|
|
||||||
|
|
||||||
<jetty.http.port>8080</jetty.http.port>
|
|
||||||
<jetty.contextpath>/${wtp.contextName}</jetty.contextpath>
|
|
||||||
|
|
||||||
<!-- main versions -->
|
|
||||||
<plantuml.version>1.2022.6</plantuml.version>
|
|
||||||
<!-- Please keep the jetty version identical with the docker image -->
|
|
||||||
<jetty.version>11.0.7</jetty.version>
|
|
||||||
<codemirror.version>5.63.0</codemirror.version>
|
|
||||||
|
|
||||||
<!-- dependencies -->
|
|
||||||
<jstl.version>1.2</jstl.version>
|
|
||||||
<apache-jsp.version>${jetty.version}</apache-jsp.version>
|
|
||||||
<jetty-annotations.version>${jetty.version}</jetty-annotations.version>
|
|
||||||
<glassfish-jstl.version>${jetty.version}</glassfish-jstl.version>
|
|
||||||
<batik-all.version>1.14</batik-all.version>
|
|
||||||
<!-- jlatexmath -->
|
|
||||||
<jlatexmath.version>1.0.7</jlatexmath.version>
|
|
||||||
<jlatexmath-font-greek.version>${jlatexmath.version}</jlatexmath-font-greek.version>
|
|
||||||
<jlatexmath-font-cyrillic.version>${jlatexmath.version}</jlatexmath-font-cyrillic.version>
|
|
||||||
|
|
||||||
<!-- Testing -->
|
|
||||||
<junit.version>4.13.2</junit.version>
|
|
||||||
<htmlunit.version>2.53.0</htmlunit.version>
|
|
||||||
<jetty-server.version>${jetty.version}</jetty-server.version>
|
|
||||||
|
|
||||||
<!-- build plugin management -->
|
<!-- build plugin management -->
|
||||||
<!-- lock down plugins versions to avoid using Maven defaults -->
|
<!-- no JDK8 support starting version 10.0.0 -->
|
||||||
<maven-clean-plugin.version>3.1.0</maven-clean-plugin.version>
|
<checkstyle.version>9.3</checkstyle.version>
|
||||||
<maven-dependency-plugin.version>3.2.0</maven-dependency-plugin.version>
|
|
||||||
<maven-resources-plugin.version>3.2.0</maven-resources-plugin.version>
|
|
||||||
<maven-compiler-plugin.version>3.8.1</maven-compiler-plugin.version>
|
|
||||||
<versions-maven-plugin.version>2.8.1</versions-maven-plugin.version>
|
|
||||||
<maven-surefire-plugin.version>2.22.2</maven-surefire-plugin.version>
|
|
||||||
<maven-war-plugin.version>3.3.2</maven-war-plugin.version>
|
|
||||||
<maven-install-plugin.version>2.5.2</maven-install-plugin.version>
|
|
||||||
<maven-deploy-plugin.version>2.8.2</maven-deploy-plugin.version>
|
|
||||||
<maven-site-plugin.version>3.9.1</maven-site-plugin.version>
|
|
||||||
<maven-project-info-reports-plugin.version>3.1.2</maven-project-info-reports-plugin.version>
|
|
||||||
<maven-checkstyle-plugin.version>3.1.2</maven-checkstyle-plugin.version>
|
|
||||||
<checkstyle.version>9.0.1</checkstyle.version>
|
|
||||||
|
|
||||||
<!-- plugins -->
|
<!-- plugins -->
|
||||||
<maven-eclipse-plugin.version>2.10</maven-eclipse-plugin.version>
|
<!-- no JDK8 support starting version 2.5.0 -->
|
||||||
<jetty-runner.version>${jetty.version}</jetty-runner.version>
|
<resources-optimizer-maven-plugin.version>2.4.4</resources-optimizer-maven-plugin.version>
|
||||||
<jetty-maven-plugin.version>${jetty.version}</jetty-maven-plugin.version>
|
|
||||||
<duplicate-finder-maven-plugin.version>1.5.0</duplicate-finder-maven-plugin.version>
|
|
||||||
<maven-javadoc-plugin.version>3.3.1</maven-javadoc-plugin.version>
|
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
|
||||||
<groupId>net.sourceforge.plantuml</groupId>
|
|
||||||
<artifactId>plantuml</artifactId>
|
|
||||||
<version>${plantuml.version}</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.webjars.npm</groupId>
|
|
||||||
<artifactId>codemirror</artifactId>
|
|
||||||
<version>${codemirror.version}</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>jakarta.servlet</groupId>
|
<groupId>jakarta.servlet</groupId>
|
||||||
<artifactId>jakarta.servlet-api</artifactId>
|
<artifactId>jakarta.servlet-api</artifactId>
|
||||||
@ -143,43 +64,8 @@
|
|||||||
</exclusion>
|
</exclusion>
|
||||||
</exclusions>
|
</exclusions>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
|
||||||
<!-- batik-all generally tends to provide duplicate resources on the classpath -->
|
|
||||||
<groupId>org.apache.xmlgraphics</groupId>
|
|
||||||
<artifactId>batik-all</artifactId>
|
|
||||||
<version>${batik-all.version}</version>
|
|
||||||
<type>pom</type>
|
|
||||||
</dependency>
|
|
||||||
<!-- jlatexmath -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.scilab.forge</groupId>
|
|
||||||
<artifactId>jlatexmath</artifactId>
|
|
||||||
<version>${jlatexmath.version}</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.scilab.forge</groupId>
|
|
||||||
<artifactId>jlatexmath-font-greek</artifactId>
|
|
||||||
<version>${jlatexmath-font-greek.version}</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.scilab.forge</groupId>
|
|
||||||
<artifactId>jlatexmath-font-cyrillic</artifactId>
|
|
||||||
<version>${jlatexmath-font-cyrillic.version}</version>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<!-- Testing -->
|
<!-- Testing -->
|
||||||
<dependency>
|
|
||||||
<groupId>junit</groupId>
|
|
||||||
<artifactId>junit</artifactId>
|
|
||||||
<version>${junit.version}</version>
|
|
||||||
<scope>test</scope>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>net.sourceforge.htmlunit</groupId>
|
|
||||||
<artifactId>htmlunit</artifactId>
|
|
||||||
<version>${htmlunit.version}</version>
|
|
||||||
<scope>test</scope>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.eclipse.jetty</groupId>
|
<groupId>org.eclipse.jetty</groupId>
|
||||||
<artifactId>jetty-server</artifactId>
|
<artifactId>jetty-server</artifactId>
|
||||||
@ -193,304 +79,4 @@
|
|||||||
</exclusions>
|
</exclusions>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
|
||||||
<finalName>plantuml</finalName>
|
|
||||||
|
|
||||||
<pluginManagement>
|
|
||||||
<plugins>
|
|
||||||
<plugin>
|
|
||||||
<artifactId>maven-clean-plugin</artifactId>
|
|
||||||
<version>${maven-clean-plugin.version}</version>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
|
||||||
<artifactId>maven-dependency-plugin</artifactId>
|
|
||||||
<version>${maven-dependency-plugin.version}</version>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
|
||||||
<artifactId>maven-resources-plugin</artifactId>
|
|
||||||
<version>${maven-resources-plugin.version}</version>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
|
||||||
<artifactId>maven-compiler-plugin</artifactId>
|
|
||||||
<version>${maven-compiler-plugin.version}</version>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
|
||||||
<artifactId>maven-surefire-plugin</artifactId>
|
|
||||||
<version>${maven-surefire-plugin.version}</version>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
|
||||||
<artifactId>maven-war-plugin</artifactId>
|
|
||||||
<version>${maven-war-plugin.version}</version>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
|
||||||
<artifactId>maven-install-plugin</artifactId>
|
|
||||||
<version>${maven-install-plugin.version}</version>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
|
||||||
<artifactId>maven-deploy-plugin</artifactId>
|
|
||||||
<version>${maven-deploy-plugin.version}</version>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
|
||||||
<artifactId>maven-site-plugin</artifactId>
|
|
||||||
<version>${maven-site-plugin.version}</version>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
|
||||||
<artifactId>maven-project-info-reports-plugin</artifactId>
|
|
||||||
<version>${maven-project-info-reports-plugin.version}</version>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-checkstyle-plugin</artifactId>
|
|
||||||
<version>${maven-checkstyle-plugin.version}</version>
|
|
||||||
<dependencies>
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.puppycrawl.tools</groupId>
|
|
||||||
<artifactId>checkstyle</artifactId>
|
|
||||||
<version>${checkstyle.version}</version>
|
|
||||||
</dependency>
|
|
||||||
</dependencies>
|
|
||||||
<configuration>
|
|
||||||
<configLocation>${basedir}/src/main/config/checkstyle.xml</configLocation>
|
|
||||||
<linkXRef>false</linkXRef>
|
|
||||||
<consoleOutput>true</consoleOutput>
|
|
||||||
<failsOnError>true</failsOnError>
|
|
||||||
</configuration>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.codehaus.mojo</groupId>
|
|
||||||
<artifactId>versions-maven-plugin</artifactId>
|
|
||||||
<version>${versions-maven-plugin.version}</version>
|
|
||||||
<configuration>
|
|
||||||
<outputFile>${project.build.directory}/outdated-dependencies.txt</outputFile>
|
|
||||||
<rulesUri>file:///${basedir}/src/main/config/rules.xml</rulesUri>
|
|
||||||
</configuration>
|
|
||||||
</plugin>
|
|
||||||
</plugins>
|
|
||||||
</pluginManagement>
|
|
||||||
|
|
||||||
<plugins>
|
|
||||||
<plugin>
|
|
||||||
<artifactId>maven-compiler-plugin</artifactId>
|
|
||||||
<version>${maven-compiler-plugin.version}</version>
|
|
||||||
<configuration>
|
|
||||||
<source>${maven.compiler.source}</source>
|
|
||||||
<target>${maven.compiler.target}</target>
|
|
||||||
</configuration>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-surefire-plugin</artifactId>
|
|
||||||
<version>${maven-surefire-plugin.version}</version>
|
|
||||||
<configuration>
|
|
||||||
<skipTests>${skipTests}</skipTests>
|
|
||||||
</configuration>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-site-plugin</artifactId>
|
|
||||||
<version>${maven-site-plugin.version}</version>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-checkstyle-plugin</artifactId>
|
|
||||||
<version>${maven-checkstyle-plugin.version}</version>
|
|
||||||
<executions>
|
|
||||||
<execution>
|
|
||||||
<?m2e execute onConfiguration,onIncremental?>
|
|
||||||
<phase>validate</phase>
|
|
||||||
<goals>
|
|
||||||
<goal>check</goal>
|
|
||||||
</goals>
|
|
||||||
</execution>
|
|
||||||
</executions>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.codehaus.mojo</groupId>
|
|
||||||
<artifactId>versions-maven-plugin</artifactId>
|
|
||||||
<version>${versions-maven-plugin.version}</version>
|
|
||||||
<executions>
|
|
||||||
<execution>
|
|
||||||
<phase>validate</phase>
|
|
||||||
<goals>
|
|
||||||
<goal>display-property-updates</goal>
|
|
||||||
</goals>
|
|
||||||
</execution>
|
|
||||||
</executions>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.basepom.maven</groupId>
|
|
||||||
<artifactId>duplicate-finder-maven-plugin</artifactId>
|
|
||||||
<version>${duplicate-finder-maven-plugin.version}</version>
|
|
||||||
<executions>
|
|
||||||
<execution>
|
|
||||||
<phase>verify</phase>
|
|
||||||
<goals>
|
|
||||||
<goal>check</goal>
|
|
||||||
</goals>
|
|
||||||
</execution>
|
|
||||||
</executions>
|
|
||||||
<configuration>
|
|
||||||
<ignoredResourcePatterns>
|
|
||||||
<ignoredResourcePattern>^about\.html$</ignoredResourcePattern>
|
|
||||||
<ignoredResourcePattern>^license/LICENSE\.dom-software\.txt$</ignoredResourcePattern>
|
|
||||||
<ignoredResourcePattern>^org/apache/batik/apps/rasterizer/resources/rasterizer\.policy$</ignoredResourcePattern>
|
|
||||||
</ignoredResourcePatterns>
|
|
||||||
</configuration>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-javadoc-plugin</artifactId>
|
|
||||||
<version>${maven-javadoc-plugin.version}</version>
|
|
||||||
<configuration>
|
|
||||||
<show>private</show>
|
|
||||||
<nohelp>true</nohelp>
|
|
||||||
<source>${java.version}</source>
|
|
||||||
<failOnWarnings>true</failOnWarnings>
|
|
||||||
</configuration>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
|
||||||
<artifactId>maven-dependency-plugin</artifactId>
|
|
||||||
<version>${maven-dependency-plugin.version}</version>
|
|
||||||
<executions>
|
|
||||||
<execution>
|
|
||||||
<?m2e execute onConfiguration,onIncremental?>
|
|
||||||
<!-- To provide webjars for the embedded jetty server for junit tests -->
|
|
||||||
<id>unpack-resources</id>
|
|
||||||
<phase>generate-test-sources</phase>
|
|
||||||
<goals>
|
|
||||||
<goal>unpack</goal>
|
|
||||||
</goals>
|
|
||||||
<configuration>
|
|
||||||
<artifactItems>
|
|
||||||
<artifactItem>
|
|
||||||
<groupId>org.webjars.npm</groupId>
|
|
||||||
<artifactId>codemirror</artifactId>
|
|
||||||
<version>${codemirror.version}</version>
|
|
||||||
<includes>**/lib/*.js,**/lib/*.css</includes>
|
|
||||||
<outputDirectory>${project.build.outputDirectory}</outputDirectory>
|
|
||||||
</artifactItem>
|
|
||||||
</artifactItems>
|
|
||||||
</configuration>
|
|
||||||
</execution>
|
|
||||||
<execution>
|
|
||||||
<phase>package</phase>
|
|
||||||
<goals>
|
|
||||||
<goal>copy</goal>
|
|
||||||
</goals>
|
|
||||||
<configuration>
|
|
||||||
<artifactItems>
|
|
||||||
<artifactItem>
|
|
||||||
<groupId>org.eclipse.jetty</groupId>
|
|
||||||
<artifactId>jetty-runner</artifactId>
|
|
||||||
<version>${jetty-runner.version}</version>
|
|
||||||
<destFileName>jetty-runner.jar</destFileName>
|
|
||||||
</artifactItem>
|
|
||||||
</artifactItems>
|
|
||||||
</configuration>
|
|
||||||
</execution>
|
|
||||||
</executions>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-eclipse-plugin</artifactId>
|
|
||||||
<version>${maven-eclipse-plugin.version}</version>
|
|
||||||
<configuration>
|
|
||||||
<wtpversion>${wtp.version}</wtpversion>
|
|
||||||
<wtpContextName>${wtp.contextName}</wtpContextName>
|
|
||||||
</configuration>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.eclipse.jetty</groupId>
|
|
||||||
<artifactId>jetty-maven-plugin</artifactId>
|
|
||||||
<version>${jetty-maven-plugin.version}</version>
|
|
||||||
<configuration>
|
|
||||||
<!-- jetty.xml
|
|
||||||
Only necessary to support old proxy.
|
|
||||||
The old proxy needs empty path segments support in URIs.
|
|
||||||
Hence: allow AMBIGUOUS_EMPTY_SEGMENT
|
|
||||||
-->
|
|
||||||
<jettyXmls>${basedir}/src/main/config/jetty.xml</jettyXmls>
|
|
||||||
<scanIntervalSeconds>5</scanIntervalSeconds>
|
|
||||||
<webApp>
|
|
||||||
<contextPath>${jetty.contextpath}</contextPath>
|
|
||||||
</webApp>
|
|
||||||
</configuration>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-war-plugin</artifactId>
|
|
||||||
<version>${maven-war-plugin.version}</version>
|
|
||||||
<configuration>
|
|
||||||
<webResources>
|
|
||||||
<resource>
|
|
||||||
<directory>${basedir}/src/main/webapp</directory>
|
|
||||||
<includes>
|
|
||||||
<include>*.jspf</include>
|
|
||||||
</includes>
|
|
||||||
<filtering>true</filtering>
|
|
||||||
</resource>
|
|
||||||
</webResources>
|
|
||||||
</configuration>
|
|
||||||
</plugin>
|
|
||||||
</plugins>
|
|
||||||
</build>
|
|
||||||
|
|
||||||
<reporting>
|
|
||||||
<plugins>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-project-info-reports-plugin</artifactId>
|
|
||||||
<version>${maven-project-info-reports-plugin.version}</version>
|
|
||||||
<reportSets>
|
|
||||||
<reportSet>
|
|
||||||
<reports>
|
|
||||||
<report>index</report>
|
|
||||||
<report>dependencies</report>
|
|
||||||
</reports>
|
|
||||||
</reportSet>
|
|
||||||
</reportSets>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.codehaus.mojo</groupId>
|
|
||||||
<artifactId>versions-maven-plugin</artifactId>
|
|
||||||
<version>${versions-maven-plugin.version}</version>
|
|
||||||
<reportSets>
|
|
||||||
<reportSet>
|
|
||||||
<reports>
|
|
||||||
<!-- <report>dependency-updates-report</report> -->
|
|
||||||
<!-- <report>plugin-updates-report</report> -->
|
|
||||||
<report>property-updates-report</report>
|
|
||||||
</reports>
|
|
||||||
</reportSet>
|
|
||||||
</reportSets>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-javadoc-plugin</artifactId>
|
|
||||||
<version>${maven-javadoc-plugin.version}</version>
|
|
||||||
<reportSets>
|
|
||||||
<reportSet>
|
|
||||||
<id>html</id>
|
|
||||||
<reports>
|
|
||||||
<report>javadoc</report>
|
|
||||||
</reports>
|
|
||||||
</reportSet>
|
|
||||||
</reportSets>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-checkstyle-plugin</artifactId>
|
|
||||||
<version>${maven-checkstyle-plugin.version}</version>
|
|
||||||
<reportSets>
|
|
||||||
<reportSet>
|
|
||||||
<reports>
|
|
||||||
<report>checkstyle</report>
|
|
||||||
<report>checkstyle-aggregate</report>
|
|
||||||
</reports>
|
|
||||||
</reportSet>
|
|
||||||
</reportSets>
|
|
||||||
</plugin>
|
|
||||||
</plugins>
|
|
||||||
</reporting>
|
|
||||||
</project>
|
</project>
|
||||||
|
688
pom.parent.xml
Normal file
@ -0,0 +1,688 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project
|
||||||
|
xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
|
||||||
|
>
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<groupId>org.sourceforge.plantuml</groupId>
|
||||||
|
<artifactId>plantumlservlet-parent</artifactId>
|
||||||
|
<version>1-SNAPSHOT</version>
|
||||||
|
<packaging>pom</packaging>
|
||||||
|
|
||||||
|
<name>PlantUML Servlet</name>
|
||||||
|
<url>https://plantuml.github.io/plantuml-server/index.html</url>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<!-- NOTE: property `java.version` has to be set inside the child pom. -->
|
||||||
|
<!-- <java.version>XX</java.version> -->
|
||||||
|
|
||||||
|
<maven.compiler.source>${java.version}</maven.compiler.source>
|
||||||
|
<maven.compiler.target>${java.version}</maven.compiler.target>
|
||||||
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
|
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Skip tests by default.
|
||||||
|
Run tests manually:
|
||||||
|
- mvn test -DskipTests=false
|
||||||
|
- mvn test -DskipTests=false -DargLine="-Dsystem.test.server=http://localhost:8080/plantuml"
|
||||||
|
-->
|
||||||
|
<skipTests>true</skipTests>
|
||||||
|
<!--
|
||||||
|
JS and CSS compression / minify
|
||||||
|
If false minify is enabled.
|
||||||
|
Dev Tipp: set to `true` and run `mvn fizzed-watcher:run` while developing the frontend
|
||||||
|
-->
|
||||||
|
<withoutCSSJSCompress>false</withoutCSSJSCompress>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
This artifact is required for:
|
||||||
|
1. EmbeddedJettyServer -> scope: test
|
||||||
|
2. Tomcat docker image -> scope: compile
|
||||||
|
BUT: Jetty docker image as well as jetty-runner will crash on runtime if
|
||||||
|
this artifact is included because it's already provided so that the
|
||||||
|
artifact would apear multiple times on the classpath.
|
||||||
|
You can test it via: `mvn jetty:run [-Dapache-jsp.scope=compile]`
|
||||||
|
Error: java.util.ServiceConfigurationError: org.apache.juli.logging.Log: org.eclipse.jetty.apache.jsp.JuliLog not a subtype
|
||||||
|
HENCE: Default is the "test" scope and for Tomcat docker image building add:
|
||||||
|
-Dapache-jsp.scope=compile
|
||||||
|
-->
|
||||||
|
<apache-jsp.scope>test</apache-jsp.scope>
|
||||||
|
|
||||||
|
<maven.build.timestamp.format>yyyyMMdd-HHmm</maven.build.timestamp.format>
|
||||||
|
<timestamp>${maven.build.timestamp}</timestamp>
|
||||||
|
|
||||||
|
<wtp.version>1.5</wtp.version>
|
||||||
|
<wtp.contextName>plantuml</wtp.contextName>
|
||||||
|
|
||||||
|
<jetty.http.port>8080</jetty.http.port>
|
||||||
|
<jetty.contextpath>/${wtp.contextName}</jetty.contextpath>
|
||||||
|
|
||||||
|
<!-- main versions -->
|
||||||
|
<plantuml.version>1.2024.7</plantuml.version>
|
||||||
|
<!-- Please keep the jetty version identical with the docker image -->
|
||||||
|
<jetty.version>11.0.18</jetty.version>
|
||||||
|
<!--
|
||||||
|
While changing the version, please update the versions in the following files as well:
|
||||||
|
- src/main/webapp/components/app-head.jsp (script import)
|
||||||
|
- src/main/webapp/components/editor/editor.js : loadMonacoCodeEditorAsync (require.config)
|
||||||
|
- src/test/java/net/sourceforge/plantuml/servlet/TestDependencies.java : testMonacoEditorWebJar (JUnit Test)
|
||||||
|
-->
|
||||||
|
<monaco-editor.version>0.36.1</monaco-editor.version>
|
||||||
|
|
||||||
|
<!-- dependencies -->
|
||||||
|
<jstl.version>1.2</jstl.version>
|
||||||
|
<apache-jsp.version>${jetty.version}</apache-jsp.version>
|
||||||
|
<jetty-annotations.version>${jetty.version}</jetty-annotations.version>
|
||||||
|
<glassfish-jstl.version>${jetty.version}</glassfish-jstl.version>
|
||||||
|
<!-- jlatexmath -->
|
||||||
|
<jlatexmath.version>1.0.7</jlatexmath.version>
|
||||||
|
<jlatexmath-font-greek.version>${jlatexmath.version}</jlatexmath-font-greek.version>
|
||||||
|
<jlatexmath-font-cyrillic.version>${jlatexmath.version}</jlatexmath-font-cyrillic.version>
|
||||||
|
<!-- PDF -->
|
||||||
|
<batik.version>1.16</batik.version>
|
||||||
|
<fop.version>2.8</fop.version>
|
||||||
|
|
||||||
|
<!-- Testing -->
|
||||||
|
<junit.version>5.9.3</junit.version>
|
||||||
|
<junit-suite.version>1.9.3</junit-suite.version>
|
||||||
|
<selenium.version>4.10.0</selenium.version>
|
||||||
|
<selenium-webdrivermanager.version>5.3.3</selenium-webdrivermanager.version>
|
||||||
|
<commons-io.version>2.11.0</commons-io.version>
|
||||||
|
<jetty-server.version>${jetty.version}</jetty-server.version>
|
||||||
|
|
||||||
|
<!-- build plugin management -->
|
||||||
|
<!-- lock down plugins versions to avoid using Maven defaults -->
|
||||||
|
<maven-clean-plugin.version>3.2.0</maven-clean-plugin.version>
|
||||||
|
<maven-dependency-plugin.version>3.5.0</maven-dependency-plugin.version>
|
||||||
|
<maven-resources-plugin.version>3.3.1</maven-resources-plugin.version>
|
||||||
|
<maven-compiler-plugin.version>3.11.0</maven-compiler-plugin.version>
|
||||||
|
<versions-maven-plugin.version>2.15.0</versions-maven-plugin.version>
|
||||||
|
<maven-surefire-plugin.version>3.1.0</maven-surefire-plugin.version>
|
||||||
|
<maven-war-plugin.version>3.3.2</maven-war-plugin.version>
|
||||||
|
<maven-install-plugin.version>3.1.1</maven-install-plugin.version>
|
||||||
|
<maven-deploy-plugin.version>3.1.1</maven-deploy-plugin.version>
|
||||||
|
<maven-site-plugin.version>3.12.1</maven-site-plugin.version>
|
||||||
|
<maven-project-info-reports-plugin.version>3.4.3</maven-project-info-reports-plugin.version>
|
||||||
|
<maven-checkstyle-plugin.version>3.2.2</maven-checkstyle-plugin.version>
|
||||||
|
<checkstyle.version>10.12.0</checkstyle.version>
|
||||||
|
|
||||||
|
<!-- plugins -->
|
||||||
|
<maven-eclipse-plugin.version>2.10</maven-eclipse-plugin.version>
|
||||||
|
<jetty-runner.version>${jetty.version}</jetty-runner.version>
|
||||||
|
<jetty-maven-plugin.version>${jetty.version}</jetty-maven-plugin.version>
|
||||||
|
<duplicate-finder-maven-plugin.version>1.5.1</duplicate-finder-maven-plugin.version>
|
||||||
|
<maven-javadoc-plugin.version>3.5.0</maven-javadoc-plugin.version>
|
||||||
|
<resources-optimizer-maven-plugin.version>2.5.6</resources-optimizer-maven-plugin.version>
|
||||||
|
<fizzed-watcher-maven-plugin.verson>1.0.6</fizzed-watcher-maven-plugin.verson>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>net.sourceforge.plantuml</groupId>
|
||||||
|
<artifactId>plantuml</artifactId>
|
||||||
|
<version>${plantuml.version}</version>
|
||||||
|
<scope>compile</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.webjars.npm</groupId>
|
||||||
|
<artifactId>monaco-editor</artifactId>
|
||||||
|
<version>${monaco-editor.version}</version>
|
||||||
|
<scope>runtime</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.eclipse.jetty</groupId>
|
||||||
|
<artifactId>apache-jsp</artifactId>
|
||||||
|
<version>${apache-jsp.version}</version>
|
||||||
|
<scope>${apache-jsp.scope}</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.eclipse.jetty</groupId>
|
||||||
|
<artifactId>jetty-annotations</artifactId>
|
||||||
|
<version>${jetty-annotations.version}</version>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
<!-- jlatexmath -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.scilab.forge</groupId>
|
||||||
|
<artifactId>jlatexmath</artifactId>
|
||||||
|
<version>${jlatexmath.version}</version>
|
||||||
|
<scope>runtime</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.scilab.forge</groupId>
|
||||||
|
<artifactId>jlatexmath-font-greek</artifactId>
|
||||||
|
<version>${jlatexmath-font-greek.version}</version>
|
||||||
|
<scope>runtime</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.scilab.forge</groupId>
|
||||||
|
<artifactId>jlatexmath-font-cyrillic</artifactId>
|
||||||
|
<version>${jlatexmath-font-cyrillic.version}</version>
|
||||||
|
<scope>runtime</scope>
|
||||||
|
</dependency>
|
||||||
|
<!-- PDF
|
||||||
|
PlantUMLs PDF generation requires:
|
||||||
|
- batik-dom
|
||||||
|
- batik-svgrasterizer (includes batik-dom)
|
||||||
|
- batik-svggen
|
||||||
|
- fop-core
|
||||||
|
-->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.xmlgraphics</groupId>
|
||||||
|
<artifactId>batik-svgrasterizer</artifactId>
|
||||||
|
<version>${batik.version}</version>
|
||||||
|
<scope>runtime</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.xmlgraphics</groupId>
|
||||||
|
<artifactId>batik-svggen</artifactId>
|
||||||
|
<version>${batik.version}</version>
|
||||||
|
<scope>runtime</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.xmlgraphics</groupId>
|
||||||
|
<artifactId>fop-core</artifactId>
|
||||||
|
<version>${fop.version}</version>
|
||||||
|
<scope>runtime</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- Testing -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.junit.jupiter</groupId>
|
||||||
|
<artifactId>junit-jupiter-api</artifactId>
|
||||||
|
<version>${junit.version}</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.junit.jupiter</groupId>
|
||||||
|
<artifactId>junit-jupiter-params</artifactId>
|
||||||
|
<version>${junit.version}</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.junit.platform</groupId>
|
||||||
|
<artifactId>junit-platform-suite-api</artifactId>
|
||||||
|
<version>${junit-suite.version}</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.seleniumhq.selenium</groupId>
|
||||||
|
<artifactId>selenium-java</artifactId>
|
||||||
|
<version>${selenium.version}</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.github.bonigarcia</groupId>
|
||||||
|
<artifactId>webdrivermanager</artifactId>
|
||||||
|
<version>${selenium-webdrivermanager.version}</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.eclipse.jetty</groupId>
|
||||||
|
<artifactId>jetty-server</artifactId>
|
||||||
|
<version>${jetty-server.version}</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.eclipse.elk</groupId>
|
||||||
|
<artifactId>org.eclipse.elk.core</artifactId>
|
||||||
|
<version>0.9.1</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.eclipse.elk</groupId>
|
||||||
|
<artifactId>org.eclipse.elk.alg.layered</artifactId>
|
||||||
|
<version>0.9.1</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.eclipse.elk</groupId>
|
||||||
|
<artifactId>org.eclipse.elk.alg.mrtree</artifactId>
|
||||||
|
<version>0.9.1</version>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<finalName>plantuml</finalName>
|
||||||
|
|
||||||
|
<pluginManagement>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<artifactId>maven-clean-plugin</artifactId>
|
||||||
|
<version>${maven-clean-plugin.version}</version>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<artifactId>maven-dependency-plugin</artifactId>
|
||||||
|
<version>${maven-dependency-plugin.version}</version>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<artifactId>maven-resources-plugin</artifactId>
|
||||||
|
<version>${maven-resources-plugin.version}</version>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
|
<version>${maven-compiler-plugin.version}</version>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<artifactId>maven-surefire-plugin</artifactId>
|
||||||
|
<version>${maven-surefire-plugin.version}</version>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<artifactId>maven-war-plugin</artifactId>
|
||||||
|
<version>${maven-war-plugin.version}</version>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<artifactId>maven-install-plugin</artifactId>
|
||||||
|
<version>${maven-install-plugin.version}</version>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<artifactId>maven-deploy-plugin</artifactId>
|
||||||
|
<version>${maven-deploy-plugin.version}</version>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<artifactId>maven-site-plugin</artifactId>
|
||||||
|
<version>${maven-site-plugin.version}</version>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<artifactId>maven-project-info-reports-plugin</artifactId>
|
||||||
|
<version>${maven-project-info-reports-plugin.version}</version>
|
||||||
|
</plugin>
|
||||||
|
<!-- set up java style rules -->
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-checkstyle-plugin</artifactId>
|
||||||
|
<version>${maven-checkstyle-plugin.version}</version>
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.puppycrawl.tools</groupId>
|
||||||
|
<artifactId>checkstyle</artifactId>
|
||||||
|
<version>${checkstyle.version}</version>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
<configuration>
|
||||||
|
<configLocation>${basedir}/src/main/config/checkstyle.xml</configLocation>
|
||||||
|
<linkXRef>false</linkXRef>
|
||||||
|
<consoleOutput>true</consoleOutput>
|
||||||
|
<failsOnError>true</failsOnError>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
<!-- set up version validation rules -->
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.codehaus.mojo</groupId>
|
||||||
|
<artifactId>versions-maven-plugin</artifactId>
|
||||||
|
<version>${versions-maven-plugin.version}</version>
|
||||||
|
<configuration>
|
||||||
|
<outputFile>${project.build.directory}/outdated-dependencies.txt</outputFile>
|
||||||
|
<rulesUri>file:///${basedir}/src/main/config/rules.xml</rulesUri>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</pluginManagement>
|
||||||
|
|
||||||
|
<plugins>
|
||||||
|
<!-- set java compile version -->
|
||||||
|
<plugin>
|
||||||
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
|
<version>${maven-compiler-plugin.version}</version>
|
||||||
|
<configuration>
|
||||||
|
<source>${maven.compiler.source}</source>
|
||||||
|
<target>${maven.compiler.target}</target>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
<!-- configure surefire to skip unit tests if skipTests is set -->
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-surefire-plugin</artifactId>
|
||||||
|
<version>${maven-surefire-plugin.version}</version>
|
||||||
|
<configuration>
|
||||||
|
<skipTests>${skipTests}</skipTests>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
<!-- configure plugin for project's reports -->
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-site-plugin</artifactId>
|
||||||
|
<version>${maven-site-plugin.version}</version>
|
||||||
|
</plugin>
|
||||||
|
<!-- setup java style checks -->
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-checkstyle-plugin</artifactId>
|
||||||
|
<version>${maven-checkstyle-plugin.version}</version>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<?m2e execute onConfiguration,onIncremental?>
|
||||||
|
<phase>validate</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>check</goal>
|
||||||
|
</goals>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
<!-- check and display possible version updates during validation
|
||||||
|
manual execution:
|
||||||
|
- mvn versions:display-property-updates
|
||||||
|
- mvn versions:display-dependency-updates
|
||||||
|
-->
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.codehaus.mojo</groupId>
|
||||||
|
<artifactId>versions-maven-plugin</artifactId>
|
||||||
|
<version>${versions-maven-plugin.version}</version>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<phase>validate</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>display-property-updates</goal>
|
||||||
|
<goal>display-dependency-updates</goal>
|
||||||
|
</goals>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
<!-- check for duplicate classes/resources
|
||||||
|
also see:
|
||||||
|
- mvn dependency:analyze
|
||||||
|
- mvn dependency:tree
|
||||||
|
-->
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.basepom.maven</groupId>
|
||||||
|
<artifactId>duplicate-finder-maven-plugin</artifactId>
|
||||||
|
<version>${duplicate-finder-maven-plugin.version}</version>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<phase>verify</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>check</goal>
|
||||||
|
</goals>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
<configuration>
|
||||||
|
<ignoredResourcePatterns>
|
||||||
|
<ignoredResourcePattern>^about\.html$</ignoredResourcePattern>
|
||||||
|
<ignoredResourcePattern>^license/LICENSE\.dom-software\.txt$</ignoredResourcePattern>
|
||||||
|
<!-- <ignoredResourcePattern>^org/apache/batik/apps/rasterizer/resources/rasterizer\.policy$</ignoredResourcePattern> -->
|
||||||
|
</ignoredResourcePatterns>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
<!-- check for missing java documentation -->
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-javadoc-plugin</artifactId>
|
||||||
|
<version>${maven-javadoc-plugin.version}</version>
|
||||||
|
<configuration>
|
||||||
|
<show>private</show>
|
||||||
|
<nohelp>true</nohelp>
|
||||||
|
<source>${java.version}</source>
|
||||||
|
<failOnWarnings>true</failOnWarnings>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
<!-- provide dependencies -->
|
||||||
|
<plugin>
|
||||||
|
<artifactId>maven-dependency-plugin</artifactId>
|
||||||
|
<version>${maven-dependency-plugin.version}</version>
|
||||||
|
<executions>
|
||||||
|
<!-- provide webjars for the embedded jetty server for junit tests -->
|
||||||
|
<execution>
|
||||||
|
<?m2e execute onConfiguration,onIncremental?>
|
||||||
|
<id>unpack-resources</id>
|
||||||
|
<phase>generate-test-sources</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>unpack</goal>
|
||||||
|
</goals>
|
||||||
|
<configuration>
|
||||||
|
<artifactItems>
|
||||||
|
<artifactItem>
|
||||||
|
<groupId>org.webjars.npm</groupId>
|
||||||
|
<artifactId>monaco-editor</artifactId>
|
||||||
|
<version>${monaco-editor.version}</version>
|
||||||
|
<includes>**/min/vs/loader.js,**/min/vs/**/*,**/min-maps/vs/**/*</includes>
|
||||||
|
<outputDirectory>${project.build.outputDirectory}</outputDirectory>
|
||||||
|
</artifactItem>
|
||||||
|
</artifactItems>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
<!-- provide jetty-runner -->
|
||||||
|
<execution>
|
||||||
|
<phase>package</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>copy</goal>
|
||||||
|
</goals>
|
||||||
|
<configuration>
|
||||||
|
<artifactItems>
|
||||||
|
<artifactItem>
|
||||||
|
<groupId>org.eclipse.jetty</groupId>
|
||||||
|
<artifactId>jetty-runner</artifactId>
|
||||||
|
<version>${jetty-runner.version}</version>
|
||||||
|
<destFileName>jetty-runner.jar</destFileName>
|
||||||
|
</artifactItem>
|
||||||
|
</artifactItems>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
<!-- configure eclipse web tools platform (WTP) -->
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-eclipse-plugin</artifactId>
|
||||||
|
<version>${maven-eclipse-plugin.version}</version>
|
||||||
|
<configuration>
|
||||||
|
<wtpversion>${wtp.version}</wtpversion>
|
||||||
|
<wtpContextName>${wtp.contextName}</wtpContextName>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
<!-- configure jetty -->
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.eclipse.jetty</groupId>
|
||||||
|
<artifactId>jetty-maven-plugin</artifactId>
|
||||||
|
<version>${jetty-maven-plugin.version}</version>
|
||||||
|
<configuration>
|
||||||
|
<!-- jetty.xml
|
||||||
|
Only necessary to support old proxy.
|
||||||
|
The old proxy needs empty path segments support in URIs.
|
||||||
|
Hence: allow AMBIGUOUS_EMPTY_SEGMENT
|
||||||
|
-->
|
||||||
|
<jettyXmls>${basedir}/src/main/config/jetty.xml</jettyXmls>
|
||||||
|
<scanIntervalSeconds>5</scanIntervalSeconds>
|
||||||
|
<webApp>
|
||||||
|
<contextPath>${jetty.contextpath}</contextPath>
|
||||||
|
</webApp>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
<!-- configure java server pages (JSP) web resources -->
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-war-plugin</artifactId>
|
||||||
|
<version>${maven-war-plugin.version}</version>
|
||||||
|
<configuration>
|
||||||
|
<webResources>
|
||||||
|
<resource>
|
||||||
|
<directory>${basedir}/src/main/webapp</directory>
|
||||||
|
<includes>
|
||||||
|
<include>*.jspf</include>
|
||||||
|
</includes>
|
||||||
|
<filtering>true</filtering>
|
||||||
|
</resource>
|
||||||
|
</webResources>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
<!-- remove minified web resources (css, js) before regeneration -->
|
||||||
|
<plugin>
|
||||||
|
<artifactId>maven-clean-plugin</artifactId>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<id>clean-minified-resources</id>
|
||||||
|
<phase>initialize</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>clean</goal>
|
||||||
|
</goals>
|
||||||
|
<configuration>
|
||||||
|
<excludeDefaultDirectories>true</excludeDefaultDirectories>
|
||||||
|
<filesets>
|
||||||
|
<fileset>
|
||||||
|
<directory>${basedir}/src/main/webapp/min</directory>
|
||||||
|
</fileset>
|
||||||
|
</filesets>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
<!-- optimize/minimize web resources (css, js) -->
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.primefaces.extensions</groupId>
|
||||||
|
<artifactId>resources-optimizer-maven-plugin</artifactId>
|
||||||
|
<version>${resources-optimizer-maven-plugin.version}</version>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<id>optimize</id>
|
||||||
|
<phase>generate-resources</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>optimize</goal>
|
||||||
|
</goals>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
<configuration>
|
||||||
|
<warningLevel>DEFAULT</warningLevel>
|
||||||
|
<failOnWarning>true</failOnWarning>
|
||||||
|
<suffix>.min</suffix>
|
||||||
|
<languageIn>ECMASCRIPT_2020</languageIn>
|
||||||
|
<languageOut>ECMASCRIPT5_STRICT</languageOut>
|
||||||
|
<emitUseStrict>true</emitUseStrict>
|
||||||
|
<resourcesSets>
|
||||||
|
<!-- combine and optimize all JS files for the web server except the PlantUML JS language features -->
|
||||||
|
<resourcesSet>
|
||||||
|
<inputDir>${basedir}/src/main/webapp</inputDir>
|
||||||
|
<includes>
|
||||||
|
<include>components/**/*.js</include>
|
||||||
|
<include>js/**/*.js</include>
|
||||||
|
</includes>
|
||||||
|
<excludes>
|
||||||
|
<exclude>js/language/**</exclude>
|
||||||
|
</excludes>
|
||||||
|
<aggregations>
|
||||||
|
<aggregation>
|
||||||
|
<withoutCompress>${withoutCSSJSCompress}</withoutCompress>
|
||||||
|
<removeIncluded>false</removeIncluded>
|
||||||
|
<outputFile>${basedir}/src/main/webapp/min/plantuml.min.js</outputFile>
|
||||||
|
</aggregation>
|
||||||
|
</aggregations>
|
||||||
|
</resourcesSet>
|
||||||
|
<!-- combine and optimize all PlantUML JS language features -->
|
||||||
|
<resourcesSet>
|
||||||
|
<inputDir>${basedir}/src/main/webapp/js/language</inputDir>
|
||||||
|
<includes>
|
||||||
|
<include>language.js</include>
|
||||||
|
<include>validation/validation.js</include>
|
||||||
|
<include>**/*.js</include>
|
||||||
|
</includes>
|
||||||
|
<aggregations>
|
||||||
|
<aggregation>
|
||||||
|
<withoutCompress>${withoutCSSJSCompress}</withoutCompress>
|
||||||
|
<removeIncluded>false</removeIncluded>
|
||||||
|
<outputFile>${basedir}/src/main/webapp/min/plantuml-language.min.js</outputFile>
|
||||||
|
</aggregation>
|
||||||
|
</aggregations>
|
||||||
|
</resourcesSet>
|
||||||
|
<!-- combine and optimize all web server style files -->
|
||||||
|
<resourcesSet>
|
||||||
|
<inputDir>${basedir}/src/main/webapp/components</inputDir>
|
||||||
|
<includes>
|
||||||
|
<include>**/*.css</include>
|
||||||
|
</includes>
|
||||||
|
<aggregations>
|
||||||
|
<aggregation>
|
||||||
|
<withoutCompress>${withoutCSSJSCompress}</withoutCompress>
|
||||||
|
<removeIncluded>false</removeIncluded>
|
||||||
|
<outputFile>${basedir}/src/main/webapp/min/plantuml.min.css</outputFile>
|
||||||
|
</aggregation>
|
||||||
|
</aggregations>
|
||||||
|
</resourcesSet>
|
||||||
|
</resourcesSets>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
<!-- watch for changes in web resources (css, js) and regenerate minified resources (only for development) -->
|
||||||
|
<plugin>
|
||||||
|
<groupId>com.fizzed</groupId>
|
||||||
|
<artifactId>fizzed-watcher-maven-plugin</artifactId>
|
||||||
|
<version>${fizzed-watcher-maven-plugin.verson}</version>
|
||||||
|
<configuration>
|
||||||
|
<watches>
|
||||||
|
<watch>
|
||||||
|
<directory>${basedir}/src/main/webapp/components</directory>
|
||||||
|
<recursive>true</recursive>
|
||||||
|
<includes>
|
||||||
|
<include>*.js</include>
|
||||||
|
<include>*.css</include>
|
||||||
|
</includes>
|
||||||
|
<excludes>
|
||||||
|
<exclude>*.min.js</exclude>
|
||||||
|
<exclude>*.min.css</exclude>
|
||||||
|
</excludes>
|
||||||
|
</watch>
|
||||||
|
</watches>
|
||||||
|
<goals>
|
||||||
|
<goal>clean:clean@clean-minified-resources</goal>
|
||||||
|
<goal>org.primefaces.extensions:resources-optimizer-maven-plugin:optimize</goal>
|
||||||
|
</goals>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
|
||||||
|
<reporting>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-project-info-reports-plugin</artifactId>
|
||||||
|
<version>${maven-project-info-reports-plugin.version}</version>
|
||||||
|
<reportSets>
|
||||||
|
<reportSet>
|
||||||
|
<reports>
|
||||||
|
<report>index</report>
|
||||||
|
<report>dependencies</report>
|
||||||
|
</reports>
|
||||||
|
</reportSet>
|
||||||
|
</reportSets>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.codehaus.mojo</groupId>
|
||||||
|
<artifactId>versions-maven-plugin</artifactId>
|
||||||
|
<version>${versions-maven-plugin.version}</version>
|
||||||
|
<reportSets>
|
||||||
|
<reportSet>
|
||||||
|
<reports>
|
||||||
|
<!-- <report>dependency-updates-report</report> -->
|
||||||
|
<!-- <report>plugin-updates-report</report> -->
|
||||||
|
<report>property-updates-report</report>
|
||||||
|
</reports>
|
||||||
|
</reportSet>
|
||||||
|
</reportSets>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-javadoc-plugin</artifactId>
|
||||||
|
<version>${maven-javadoc-plugin.version}</version>
|
||||||
|
<reportSets>
|
||||||
|
<reportSet>
|
||||||
|
<id>html</id>
|
||||||
|
<reports>
|
||||||
|
<report>javadoc</report>
|
||||||
|
</reports>
|
||||||
|
</reportSet>
|
||||||
|
</reportSets>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-checkstyle-plugin</artifactId>
|
||||||
|
<version>${maven-checkstyle-plugin.version}</version>
|
||||||
|
<reportSets>
|
||||||
|
<reportSet>
|
||||||
|
<reports>
|
||||||
|
<report>checkstyle</report>
|
||||||
|
<report>checkstyle-aggregate</report>
|
||||||
|
</reports>
|
||||||
|
</reportSet>
|
||||||
|
</reportSets>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</reporting>
|
||||||
|
</project>
|
458
pom.xml
@ -6,463 +6,17 @@
|
|||||||
>
|
>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<parent>
|
||||||
<groupId>org.sourceforge.plantuml</groupId>
|
<groupId>org.sourceforge.plantuml</groupId>
|
||||||
<artifactId>plantumlservlet</artifactId>
|
<artifactId>plantumlservlet-parent</artifactId>
|
||||||
<version>1-SNAPSHOT</version>
|
<version>1-SNAPSHOT</version>
|
||||||
<packaging>war</packaging>
|
<relativePath>pom.parent.xml</relativePath>
|
||||||
|
</parent>
|
||||||
|
|
||||||
<name>PlantUML Servlet</name>
|
<artifactId>plantumlservlet</artifactId>
|
||||||
<url>https://plantuml.github.io/plantuml-server/index.html</url>
|
<packaging>war</packaging>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<java.version>11</java.version>
|
<java.version>11</java.version>
|
||||||
<maven.compiler.source>${java.version}</maven.compiler.source>
|
|
||||||
<maven.compiler.target>${java.version}</maven.compiler.target>
|
|
||||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
|
||||||
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
|
||||||
|
|
||||||
<!--
|
|
||||||
Skip tests by default.
|
|
||||||
Run tests manually:
|
|
||||||
- mvn test -DskipTests=false
|
|
||||||
- mvn test -DskipTests=false -DargLine="-Dsystem.test.server=http://localhost:8080/plantuml"
|
|
||||||
-->
|
|
||||||
<skipTests>true</skipTests>
|
|
||||||
|
|
||||||
<!--
|
|
||||||
This artifact is required for:
|
|
||||||
1. EmbeddedJettyServer -> scope: test
|
|
||||||
2. Tomcat docker image -> scope: compile
|
|
||||||
BUT: Jetty docker image as well as jetty-runner will crash on runtime if
|
|
||||||
this artifact is included because it's already provided so that the
|
|
||||||
artifact would apear multiple times on the classpath.
|
|
||||||
You can test it via: `mvn jetty:run [-Dapache-jsp.scope=compile]`
|
|
||||||
Error: java.util.ServiceConfigurationError: org.apache.juli.logging.Log: org.eclipse.jetty.apache.jsp.JuliLog not a subtype
|
|
||||||
HENCE: Default is the "test" scope and for Tomcat docker image building add:
|
|
||||||
-Dapache-jsp.scope=compile
|
|
||||||
-->
|
|
||||||
<apache-jsp.scope>test</apache-jsp.scope>
|
|
||||||
|
|
||||||
<maven.build.timestamp.format>yyyyMMdd-HHmm</maven.build.timestamp.format>
|
|
||||||
<timestamp>${maven.build.timestamp}</timestamp>
|
|
||||||
|
|
||||||
<wtp.version>1.5</wtp.version>
|
|
||||||
<wtp.contextName>plantuml</wtp.contextName>
|
|
||||||
|
|
||||||
<jetty.http.port>8080</jetty.http.port>
|
|
||||||
<jetty.contextpath>/${wtp.contextName}</jetty.contextpath>
|
|
||||||
|
|
||||||
<!-- main versions -->
|
|
||||||
<plantuml.version>1.2022.6</plantuml.version>
|
|
||||||
<!-- Please keep the jetty version identical with the docker image -->
|
|
||||||
<jetty.version>11.0.7</jetty.version>
|
|
||||||
<codemirror.version>5.63.0</codemirror.version>
|
|
||||||
|
|
||||||
<!-- dependencies -->
|
|
||||||
<jstl.version>1.2</jstl.version>
|
|
||||||
<apache-jsp.version>${jetty.version}</apache-jsp.version>
|
|
||||||
<jetty-annotations.version>${jetty.version}</jetty-annotations.version>
|
|
||||||
<glassfish-jstl.version>${jetty.version}</glassfish-jstl.version>
|
|
||||||
<batik-all.version>1.14</batik-all.version>
|
|
||||||
<!-- jlatexmath -->
|
|
||||||
<jlatexmath.version>1.0.7</jlatexmath.version>
|
|
||||||
<jlatexmath-font-greek.version>${jlatexmath.version}</jlatexmath-font-greek.version>
|
|
||||||
<jlatexmath-font-cyrillic.version>${jlatexmath.version}</jlatexmath-font-cyrillic.version>
|
|
||||||
|
|
||||||
<!-- Testing -->
|
|
||||||
<junit.version>4.13.2</junit.version>
|
|
||||||
<htmlunit.version>2.53.0</htmlunit.version>
|
|
||||||
<jetty-server.version>${jetty.version}</jetty-server.version>
|
|
||||||
|
|
||||||
<!-- build plugin management -->
|
|
||||||
<!-- lock down plugins versions to avoid using Maven defaults -->
|
|
||||||
<maven-clean-plugin.version>3.1.0</maven-clean-plugin.version>
|
|
||||||
<maven-dependency-plugin.version>3.2.0</maven-dependency-plugin.version>
|
|
||||||
<maven-resources-plugin.version>3.2.0</maven-resources-plugin.version>
|
|
||||||
<maven-compiler-plugin.version>3.8.1</maven-compiler-plugin.version>
|
|
||||||
<versions-maven-plugin.version>2.8.1</versions-maven-plugin.version>
|
|
||||||
<maven-surefire-plugin.version>2.22.2</maven-surefire-plugin.version>
|
|
||||||
<maven-war-plugin.version>3.3.2</maven-war-plugin.version>
|
|
||||||
<maven-install-plugin.version>2.5.2</maven-install-plugin.version>
|
|
||||||
<maven-deploy-plugin.version>2.8.2</maven-deploy-plugin.version>
|
|
||||||
<maven-site-plugin.version>3.9.1</maven-site-plugin.version>
|
|
||||||
<maven-project-info-reports-plugin.version>3.1.2</maven-project-info-reports-plugin.version>
|
|
||||||
<maven-checkstyle-plugin.version>3.1.2</maven-checkstyle-plugin.version>
|
|
||||||
<checkstyle.version>9.0.1</checkstyle.version>
|
|
||||||
|
|
||||||
<!-- plugins -->
|
|
||||||
<maven-eclipse-plugin.version>2.10</maven-eclipse-plugin.version>
|
|
||||||
<jetty-runner.version>${jetty.version}</jetty-runner.version>
|
|
||||||
<jetty-maven-plugin.version>${jetty.version}</jetty-maven-plugin.version>
|
|
||||||
<duplicate-finder-maven-plugin.version>1.5.0</duplicate-finder-maven-plugin.version>
|
|
||||||
<maven-javadoc-plugin.version>3.3.1</maven-javadoc-plugin.version>
|
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
<dependencies>
|
|
||||||
<dependency>
|
|
||||||
<groupId>net.sourceforge.plantuml</groupId>
|
|
||||||
<artifactId>plantuml</artifactId>
|
|
||||||
<version>${plantuml.version}</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.webjars.npm</groupId>
|
|
||||||
<artifactId>codemirror</artifactId>
|
|
||||||
<version>${codemirror.version}</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.eclipse.jetty</groupId>
|
|
||||||
<artifactId>apache-jsp</artifactId>
|
|
||||||
<version>${apache-jsp.version}</version>
|
|
||||||
<scope>${apache-jsp.scope}</scope>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.eclipse.jetty</groupId>
|
|
||||||
<artifactId>jetty-annotations</artifactId>
|
|
||||||
<version>${jetty-annotations.version}</version>
|
|
||||||
<scope>provided</scope>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<!-- batik-all generally tends to provide duplicate resources on the classpath -->
|
|
||||||
<groupId>org.apache.xmlgraphics</groupId>
|
|
||||||
<artifactId>batik-all</artifactId>
|
|
||||||
<version>${batik-all.version}</version>
|
|
||||||
<type>pom</type>
|
|
||||||
</dependency>
|
|
||||||
<!-- jlatexmath -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.scilab.forge</groupId>
|
|
||||||
<artifactId>jlatexmath</artifactId>
|
|
||||||
<version>${jlatexmath.version}</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.scilab.forge</groupId>
|
|
||||||
<artifactId>jlatexmath-font-greek</artifactId>
|
|
||||||
<version>${jlatexmath-font-greek.version}</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.scilab.forge</groupId>
|
|
||||||
<artifactId>jlatexmath-font-cyrillic</artifactId>
|
|
||||||
<version>${jlatexmath-font-cyrillic.version}</version>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<!-- Testing -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>junit</groupId>
|
|
||||||
<artifactId>junit</artifactId>
|
|
||||||
<version>${junit.version}</version>
|
|
||||||
<scope>test</scope>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>net.sourceforge.htmlunit</groupId>
|
|
||||||
<artifactId>htmlunit</artifactId>
|
|
||||||
<version>${htmlunit.version}</version>
|
|
||||||
<scope>test</scope>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.eclipse.jetty</groupId>
|
|
||||||
<artifactId>jetty-server</artifactId>
|
|
||||||
<version>${jetty-server.version}</version>
|
|
||||||
<scope>test</scope>
|
|
||||||
</dependency>
|
|
||||||
</dependencies>
|
|
||||||
|
|
||||||
<build>
|
|
||||||
<finalName>plantuml</finalName>
|
|
||||||
|
|
||||||
<pluginManagement>
|
|
||||||
<plugins>
|
|
||||||
<plugin>
|
|
||||||
<artifactId>maven-clean-plugin</artifactId>
|
|
||||||
<version>${maven-clean-plugin.version}</version>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
|
||||||
<artifactId>maven-dependency-plugin</artifactId>
|
|
||||||
<version>${maven-dependency-plugin.version}</version>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
|
||||||
<artifactId>maven-resources-plugin</artifactId>
|
|
||||||
<version>${maven-resources-plugin.version}</version>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
|
||||||
<artifactId>maven-compiler-plugin</artifactId>
|
|
||||||
<version>${maven-compiler-plugin.version}</version>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
|
||||||
<artifactId>maven-surefire-plugin</artifactId>
|
|
||||||
<version>${maven-surefire-plugin.version}</version>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
|
||||||
<artifactId>maven-war-plugin</artifactId>
|
|
||||||
<version>${maven-war-plugin.version}</version>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
|
||||||
<artifactId>maven-install-plugin</artifactId>
|
|
||||||
<version>${maven-install-plugin.version}</version>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
|
||||||
<artifactId>maven-deploy-plugin</artifactId>
|
|
||||||
<version>${maven-deploy-plugin.version}</version>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
|
||||||
<artifactId>maven-site-plugin</artifactId>
|
|
||||||
<version>${maven-site-plugin.version}</version>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
|
||||||
<artifactId>maven-project-info-reports-plugin</artifactId>
|
|
||||||
<version>${maven-project-info-reports-plugin.version}</version>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-checkstyle-plugin</artifactId>
|
|
||||||
<version>${maven-checkstyle-plugin.version}</version>
|
|
||||||
<dependencies>
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.puppycrawl.tools</groupId>
|
|
||||||
<artifactId>checkstyle</artifactId>
|
|
||||||
<version>${checkstyle.version}</version>
|
|
||||||
</dependency>
|
|
||||||
</dependencies>
|
|
||||||
<configuration>
|
|
||||||
<configLocation>${basedir}/src/main/config/checkstyle.xml</configLocation>
|
|
||||||
<linkXRef>false</linkXRef>
|
|
||||||
<consoleOutput>true</consoleOutput>
|
|
||||||
<failsOnError>true</failsOnError>
|
|
||||||
</configuration>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.codehaus.mojo</groupId>
|
|
||||||
<artifactId>versions-maven-plugin</artifactId>
|
|
||||||
<version>${versions-maven-plugin.version}</version>
|
|
||||||
<configuration>
|
|
||||||
<outputFile>${project.build.directory}/outdated-dependencies.txt</outputFile>
|
|
||||||
<rulesUri>file:///${basedir}/src/main/config/rules.xml</rulesUri>
|
|
||||||
</configuration>
|
|
||||||
</plugin>
|
|
||||||
</plugins>
|
|
||||||
</pluginManagement>
|
|
||||||
|
|
||||||
<plugins>
|
|
||||||
<plugin>
|
|
||||||
<artifactId>maven-compiler-plugin</artifactId>
|
|
||||||
<version>${maven-compiler-plugin.version}</version>
|
|
||||||
<configuration>
|
|
||||||
<source>${maven.compiler.source}</source>
|
|
||||||
<target>${maven.compiler.target}</target>
|
|
||||||
</configuration>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-surefire-plugin</artifactId>
|
|
||||||
<version>${maven-surefire-plugin.version}</version>
|
|
||||||
<configuration>
|
|
||||||
<skipTests>${skipTests}</skipTests>
|
|
||||||
</configuration>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-site-plugin</artifactId>
|
|
||||||
<version>${maven-site-plugin.version}</version>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-checkstyle-plugin</artifactId>
|
|
||||||
<version>${maven-checkstyle-plugin.version}</version>
|
|
||||||
<executions>
|
|
||||||
<execution>
|
|
||||||
<?m2e execute onConfiguration,onIncremental?>
|
|
||||||
<phase>validate</phase>
|
|
||||||
<goals>
|
|
||||||
<goal>check</goal>
|
|
||||||
</goals>
|
|
||||||
</execution>
|
|
||||||
</executions>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.codehaus.mojo</groupId>
|
|
||||||
<artifactId>versions-maven-plugin</artifactId>
|
|
||||||
<version>${versions-maven-plugin.version}</version>
|
|
||||||
<executions>
|
|
||||||
<execution>
|
|
||||||
<phase>validate</phase>
|
|
||||||
<goals>
|
|
||||||
<goal>display-property-updates</goal>
|
|
||||||
</goals>
|
|
||||||
</execution>
|
|
||||||
</executions>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.basepom.maven</groupId>
|
|
||||||
<artifactId>duplicate-finder-maven-plugin</artifactId>
|
|
||||||
<version>${duplicate-finder-maven-plugin.version}</version>
|
|
||||||
<executions>
|
|
||||||
<execution>
|
|
||||||
<phase>verify</phase>
|
|
||||||
<goals>
|
|
||||||
<goal>check</goal>
|
|
||||||
</goals>
|
|
||||||
</execution>
|
|
||||||
</executions>
|
|
||||||
<configuration>
|
|
||||||
<ignoredResourcePatterns>
|
|
||||||
<ignoredResourcePattern>^about\.html$</ignoredResourcePattern>
|
|
||||||
<ignoredResourcePattern>^license/LICENSE\.dom-software\.txt$</ignoredResourcePattern>
|
|
||||||
<ignoredResourcePattern>^org/apache/batik/apps/rasterizer/resources/rasterizer\.policy$</ignoredResourcePattern>
|
|
||||||
</ignoredResourcePatterns>
|
|
||||||
</configuration>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-javadoc-plugin</artifactId>
|
|
||||||
<version>${maven-javadoc-plugin.version}</version>
|
|
||||||
<configuration>
|
|
||||||
<show>private</show>
|
|
||||||
<nohelp>true</nohelp>
|
|
||||||
<source>${java.version}</source>
|
|
||||||
<failOnWarnings>true</failOnWarnings>
|
|
||||||
</configuration>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
|
||||||
<artifactId>maven-dependency-plugin</artifactId>
|
|
||||||
<version>${maven-dependency-plugin.version}</version>
|
|
||||||
<executions>
|
|
||||||
<execution>
|
|
||||||
<?m2e execute onConfiguration,onIncremental?>
|
|
||||||
<!-- To provide webjars for the embedded jetty server for junit tests -->
|
|
||||||
<id>unpack-resources</id>
|
|
||||||
<phase>generate-test-sources</phase>
|
|
||||||
<goals>
|
|
||||||
<goal>unpack</goal>
|
|
||||||
</goals>
|
|
||||||
<configuration>
|
|
||||||
<artifactItems>
|
|
||||||
<artifactItem>
|
|
||||||
<groupId>org.webjars.npm</groupId>
|
|
||||||
<artifactId>codemirror</artifactId>
|
|
||||||
<version>${codemirror.version}</version>
|
|
||||||
<includes>**/lib/*.js,**/lib/*.css</includes>
|
|
||||||
<outputDirectory>${project.build.outputDirectory}</outputDirectory>
|
|
||||||
</artifactItem>
|
|
||||||
</artifactItems>
|
|
||||||
</configuration>
|
|
||||||
</execution>
|
|
||||||
<execution>
|
|
||||||
<phase>package</phase>
|
|
||||||
<goals>
|
|
||||||
<goal>copy</goal>
|
|
||||||
</goals>
|
|
||||||
<configuration>
|
|
||||||
<artifactItems>
|
|
||||||
<artifactItem>
|
|
||||||
<groupId>org.eclipse.jetty</groupId>
|
|
||||||
<artifactId>jetty-runner</artifactId>
|
|
||||||
<version>${jetty-runner.version}</version>
|
|
||||||
<destFileName>jetty-runner.jar</destFileName>
|
|
||||||
</artifactItem>
|
|
||||||
</artifactItems>
|
|
||||||
</configuration>
|
|
||||||
</execution>
|
|
||||||
</executions>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-eclipse-plugin</artifactId>
|
|
||||||
<version>${maven-eclipse-plugin.version}</version>
|
|
||||||
<configuration>
|
|
||||||
<wtpversion>${wtp.version}</wtpversion>
|
|
||||||
<wtpContextName>${wtp.contextName}</wtpContextName>
|
|
||||||
</configuration>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.eclipse.jetty</groupId>
|
|
||||||
<artifactId>jetty-maven-plugin</artifactId>
|
|
||||||
<version>${jetty-maven-plugin.version}</version>
|
|
||||||
<configuration>
|
|
||||||
<!-- jetty.xml
|
|
||||||
Only necessary to support old proxy.
|
|
||||||
The old proxy needs empty path segments support in URIs.
|
|
||||||
Hence: allow AMBIGUOUS_EMPTY_SEGMENT
|
|
||||||
-->
|
|
||||||
<jettyXmls>${basedir}/src/main/config/jetty.xml</jettyXmls>
|
|
||||||
<scanIntervalSeconds>5</scanIntervalSeconds>
|
|
||||||
<webApp>
|
|
||||||
<contextPath>${jetty.contextpath}</contextPath>
|
|
||||||
</webApp>
|
|
||||||
</configuration>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-war-plugin</artifactId>
|
|
||||||
<version>${maven-war-plugin.version}</version>
|
|
||||||
<configuration>
|
|
||||||
<webResources>
|
|
||||||
<resource>
|
|
||||||
<directory>${basedir}/src/main/webapp</directory>
|
|
||||||
<includes>
|
|
||||||
<include>*.jspf</include>
|
|
||||||
</includes>
|
|
||||||
<filtering>true</filtering>
|
|
||||||
</resource>
|
|
||||||
</webResources>
|
|
||||||
</configuration>
|
|
||||||
</plugin>
|
|
||||||
</plugins>
|
|
||||||
</build>
|
|
||||||
|
|
||||||
<reporting>
|
|
||||||
<plugins>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-project-info-reports-plugin</artifactId>
|
|
||||||
<version>${maven-project-info-reports-plugin.version}</version>
|
|
||||||
<reportSets>
|
|
||||||
<reportSet>
|
|
||||||
<reports>
|
|
||||||
<report>index</report>
|
|
||||||
<report>dependencies</report>
|
|
||||||
</reports>
|
|
||||||
</reportSet>
|
|
||||||
</reportSets>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.codehaus.mojo</groupId>
|
|
||||||
<artifactId>versions-maven-plugin</artifactId>
|
|
||||||
<version>${versions-maven-plugin.version}</version>
|
|
||||||
<reportSets>
|
|
||||||
<reportSet>
|
|
||||||
<reports>
|
|
||||||
<!-- <report>dependency-updates-report</report> -->
|
|
||||||
<!-- <report>plugin-updates-report</report> -->
|
|
||||||
<report>property-updates-report</report>
|
|
||||||
</reports>
|
|
||||||
</reportSet>
|
|
||||||
</reportSets>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-javadoc-plugin</artifactId>
|
|
||||||
<version>${maven-javadoc-plugin.version}</version>
|
|
||||||
<reportSets>
|
|
||||||
<reportSet>
|
|
||||||
<id>html</id>
|
|
||||||
<reports>
|
|
||||||
<report>javadoc</report>
|
|
||||||
</reports>
|
|
||||||
</reportSet>
|
|
||||||
</reportSets>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-checkstyle-plugin</artifactId>
|
|
||||||
<version>${maven-checkstyle-plugin.version}</version>
|
|
||||||
<reportSets>
|
|
||||||
<reportSet>
|
|
||||||
<reports>
|
|
||||||
<report>checkstyle</report>
|
|
||||||
<report>checkstyle-aggregate</report>
|
|
||||||
</reports>
|
|
||||||
</reportSet>
|
|
||||||
</reportSets>
|
|
||||||
</plugin>
|
|
||||||
</plugins>
|
|
||||||
</reporting>
|
|
||||||
</project>
|
</project>
|
||||||
|
Before Width: | Height: | Size: 46 KiB |
@ -15,6 +15,8 @@
|
|||||||
<module name="LineLength">
|
<module name="LineLength">
|
||||||
<property name="max" value="120" />
|
<property name="max" value="120" />
|
||||||
<property name="tabWidth" value="4" />
|
<property name="tabWidth" value="4" />
|
||||||
|
<!-- ignore java doc including links, e.g.: `* @see <a href="https://...">PlantUML Code</a>` -->
|
||||||
|
<property name="ignorePattern" value="^\s*(\*|//).*@see\s.*?\shref=.*$"/>
|
||||||
</module>
|
</module>
|
||||||
<module name="NewlineAtEndOfFile">
|
<module name="NewlineAtEndOfFile">
|
||||||
<metadata name="net.sf.eclipsecs.core.lastEnabledSeverity" value="inherit" />
|
<metadata name="net.sf.eclipsecs.core.lastEnabledSeverity" value="inherit" />
|
||||||
@ -25,6 +27,7 @@
|
|||||||
<property name="message" value="Line has trailing spaces." />
|
<property name="message" value="Line has trailing spaces." />
|
||||||
</module>
|
</module>
|
||||||
<module name="Translation" />
|
<module name="Translation" />
|
||||||
|
<module name="SuppressWarningsFilter" />
|
||||||
<module name="TreeWalker">
|
<module name="TreeWalker">
|
||||||
<module name="ArrayTypeStyle" />
|
<module name="ArrayTypeStyle" />
|
||||||
<module name="AvoidInlineConditionals">
|
<module name="AvoidInlineConditionals">
|
||||||
@ -113,5 +116,6 @@
|
|||||||
<module name="VisibilityModifier" />
|
<module name="VisibilityModifier" />
|
||||||
<module name="WhitespaceAfter" />
|
<module name="WhitespaceAfter" />
|
||||||
<module name="WhitespaceAround" />
|
<module name="WhitespaceAround" />
|
||||||
|
<module name="SuppressWarningsHolder" />
|
||||||
</module>
|
</module>
|
||||||
</module>
|
</module>
|
||||||
|
@ -64,7 +64,8 @@
|
|||||||
</Array>
|
</Array>
|
||||||
</Arg>
|
</Arg>
|
||||||
|
|
||||||
<!-- Change port according to property. Default is 8080 -->
|
<!-- Change host and port according to properties. Default is 0.0.0.0 and 8080. -->
|
||||||
|
<Set name="host"><Property name="jetty.http.host" deprecated="jetty.host" default="0.0.0.0" /></Set>
|
||||||
<Set name="port"><Property name="jetty.http.port" deprecated="jetty.port" default="8080" /></Set>
|
<Set name="port"><Property name="jetty.http.port" deprecated="jetty.port" default="8080" /></Set>
|
||||||
</New>
|
</New>
|
||||||
|
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
<ignoreVersion type="regex">(?i).*RC(?:-?\d+)?</ignoreVersion>
|
<ignoreVersion type="regex">(?i).*RC(?:-?\d+)?</ignoreVersion>
|
||||||
<ignoreVersion type="regex">(?i).*CR(?:-?\d+)?</ignoreVersion>
|
<ignoreVersion type="regex">(?i).*CR(?:-?\d+)?</ignoreVersion>
|
||||||
<ignoreVersion type="regex">(?i).*M(?:-?\d+)?</ignoreVersion>
|
<ignoreVersion type="regex">(?i).*M(?:-?\d+)?</ignoreVersion>
|
||||||
|
<ignoreVersion type="regex">(?i).*-dev((?:-?\d+)|(?:\.20\d{6}))?</ignoreVersion>
|
||||||
</ignoreVersions>
|
</ignoreVersions>
|
||||||
<rules>
|
<rules>
|
||||||
<rule groupId="net.sourceforge.plantuml" artifactId="plantuml" comparisonMethod="maven">
|
<rule groupId="net.sourceforge.plantuml" artifactId="plantuml" comparisonMethod="maven">
|
||||||
|
@ -0,0 +1,151 @@
|
|||||||
|
/* ========================================================================
|
||||||
|
* PlantUML : a free UML diagram generator
|
||||||
|
* ========================================================================
|
||||||
|
*
|
||||||
|
* Project Info: https://plantuml.com
|
||||||
|
*
|
||||||
|
* This file is part of PlantUML.
|
||||||
|
*
|
||||||
|
* PlantUML is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* PlantUML distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||||
|
* License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
|
||||||
|
* USA.
|
||||||
|
*/
|
||||||
|
package net.sourceforge.plantuml.servlet;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
import jakarta.servlet.ServletException;
|
||||||
|
import jakarta.servlet.http.HttpServlet;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
import net.sourceforge.plantuml.code.Transcoder;
|
||||||
|
import net.sourceforge.plantuml.code.TranscoderUtil;
|
||||||
|
import net.sourceforge.plantuml.servlet.utility.UrlDataExtractor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ASCII encoder and decoder servlet for the webapp.
|
||||||
|
* This servlet encodes the diagram in text format or decodes the compressed diagram string.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("SERIAL")
|
||||||
|
public class AsciiCoderServlet extends HttpServlet {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Regex pattern to fetch last part of the URL.
|
||||||
|
*/
|
||||||
|
private static final Pattern URL_PATTERN = Pattern.compile("^.*[^a-zA-Z0-9\\-\\_]([a-zA-Z0-9\\-\\_]+)");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Context path from the servlet mapping URL pattern.
|
||||||
|
*
|
||||||
|
* @return servlet context path without leading or tailing slash
|
||||||
|
*/
|
||||||
|
protected String getServletContextPath() {
|
||||||
|
return "coder";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
|
||||||
|
request.setCharacterEncoding("UTF-8");
|
||||||
|
|
||||||
|
final String encodedText = getEncodedTextFromUrl(request);
|
||||||
|
|
||||||
|
String text = "";
|
||||||
|
try {
|
||||||
|
text = getTranscoder().decode(encodedText);
|
||||||
|
} catch (Exception e) {
|
||||||
|
response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
response.addHeader("Access-Control-Allow-Origin", "*");
|
||||||
|
response.setContentType("text/plain;charset=UTF-8");
|
||||||
|
response.getWriter().write(text);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void doPost(
|
||||||
|
HttpServletRequest request,
|
||||||
|
HttpServletResponse response
|
||||||
|
) throws ServletException, IOException {
|
||||||
|
request.setCharacterEncoding("UTF-8");
|
||||||
|
|
||||||
|
// read textual diagram source from request body
|
||||||
|
final StringBuilder uml = new StringBuilder();
|
||||||
|
try (BufferedReader in = request.getReader()) {
|
||||||
|
String line;
|
||||||
|
while ((line = in.readLine()) != null) {
|
||||||
|
uml.append(line).append('\n');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// encode textual diagram source
|
||||||
|
String encoded = "";
|
||||||
|
try {
|
||||||
|
encoded = getTranscoder().encode(uml.toString());
|
||||||
|
} catch (Exception e) {
|
||||||
|
response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
response.addHeader("Access-Control-Allow-Origin", "*");
|
||||||
|
response.setContentType("text/plain;charset=UTF-8");
|
||||||
|
response.getWriter().write(encoded);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get PlantUML transcoder.
|
||||||
|
*
|
||||||
|
* @return transcoder instance
|
||||||
|
*/
|
||||||
|
protected Transcoder getTranscoder() {
|
||||||
|
return TranscoderUtil.getDefaultTranscoder();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get encoded textual diagram source from URL.
|
||||||
|
*
|
||||||
|
* @param request http request which contains the source URL
|
||||||
|
*
|
||||||
|
* @return if successful encoded textual diagram source from URL; otherwise empty string
|
||||||
|
*
|
||||||
|
* @throws IOException if an input or output exception occurred
|
||||||
|
*/
|
||||||
|
protected String getEncodedTextFromUrl(HttpServletRequest request) throws IOException {
|
||||||
|
// textual diagram source from request URI
|
||||||
|
String url = request.getRequestURI();
|
||||||
|
final String contextpath = "/" + getServletContextPath() + "/";
|
||||||
|
if (url.contains(contextpath) && !url.endsWith(contextpath)) {
|
||||||
|
final String encoded = UrlDataExtractor.getEncodedDiagram(request.getRequestURI(), "");
|
||||||
|
if (!encoded.isEmpty()) {
|
||||||
|
return encoded;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// textual diagram source from "url" parameter
|
||||||
|
url = request.getParameter("url");
|
||||||
|
if (url != null && !url.trim().isEmpty()) {
|
||||||
|
// Catch the last part of the URL if necessary
|
||||||
|
final Matcher matcher = URL_PATTERN.matcher(url);
|
||||||
|
if (matcher.find()) {
|
||||||
|
url = matcher.group(1);
|
||||||
|
}
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
// nothing found
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -23,12 +23,14 @@
|
|||||||
*/
|
*/
|
||||||
package net.sourceforge.plantuml.servlet;
|
package net.sourceforge.plantuml.servlet;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.FileReader;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.PrintWriter;
|
import java.io.PrintWriter;
|
||||||
import java.util.Collections;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.Collection;
|
||||||
import java.util.Map;
|
import java.util.List;
|
||||||
|
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
@ -38,14 +40,16 @@ import net.sourceforge.plantuml.ErrorUml;
|
|||||||
import net.sourceforge.plantuml.FileFormat;
|
import net.sourceforge.plantuml.FileFormat;
|
||||||
import net.sourceforge.plantuml.FileFormatOption;
|
import net.sourceforge.plantuml.FileFormatOption;
|
||||||
import net.sourceforge.plantuml.NullOutputStream;
|
import net.sourceforge.plantuml.NullOutputStream;
|
||||||
import net.sourceforge.plantuml.OptionFlags;
|
|
||||||
import net.sourceforge.plantuml.SourceStringReader;
|
import net.sourceforge.plantuml.SourceStringReader;
|
||||||
import net.sourceforge.plantuml.StringUtils;
|
import net.sourceforge.plantuml.StringUtils;
|
||||||
import net.sourceforge.plantuml.code.Base64Coder;
|
import net.sourceforge.plantuml.utils.Base64Coder;
|
||||||
import net.sourceforge.plantuml.core.Diagram;
|
import net.sourceforge.plantuml.core.Diagram;
|
||||||
import net.sourceforge.plantuml.core.DiagramDescription;
|
import net.sourceforge.plantuml.core.DiagramDescription;
|
||||||
import net.sourceforge.plantuml.core.ImageData;
|
import net.sourceforge.plantuml.core.ImageData;
|
||||||
import net.sourceforge.plantuml.error.PSystemError;
|
import net.sourceforge.plantuml.error.PSystemError;
|
||||||
|
import net.sourceforge.plantuml.preproc.Defines;
|
||||||
|
import net.sourceforge.plantuml.security.SecurityProfile;
|
||||||
|
import net.sourceforge.plantuml.security.SecurityUtils;
|
||||||
import net.sourceforge.plantuml.version.Version;
|
import net.sourceforge.plantuml.version.Version;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -54,27 +58,33 @@ import net.sourceforge.plantuml.version.Version;
|
|||||||
*/
|
*/
|
||||||
public class DiagramResponse {
|
public class DiagramResponse {
|
||||||
|
|
||||||
/**
|
private static class BlockSelection {
|
||||||
* {@link FileFormat} to http content type mapping.
|
private final BlockUml block;
|
||||||
*/
|
private final int systemIdx;
|
||||||
private static final Map<FileFormat, String> CONTENT_TYPE;
|
|
||||||
|
BlockSelection(BlockUml blk, int idx) {
|
||||||
|
block = blk;
|
||||||
|
systemIdx = idx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* X-Powered-By http header value included in every response by default.
|
* X-Powered-By http header value included in every response by default.
|
||||||
*/
|
*/
|
||||||
private static final String POWERED_BY = "PlantUML Version " + Version.versionString();
|
private static final String POWERED_BY = "PlantUML Version " + Version.versionString();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PLANTUML_CONFIG_FILE content.
|
||||||
|
*/
|
||||||
|
private static final List<String> CONFIG = new ArrayList<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cache/flag to ensure that the `init()` method is called only once.
|
||||||
|
*/
|
||||||
|
private static boolean initialized = false;
|
||||||
|
|
||||||
static {
|
static {
|
||||||
OptionFlags.ALLOW_INCLUDE = false;
|
init();
|
||||||
if ("true".equalsIgnoreCase(System.getenv("ALLOW_PLANTUML_INCLUDE"))) {
|
|
||||||
OptionFlags.ALLOW_INCLUDE = true;
|
|
||||||
}
|
|
||||||
CONTENT_TYPE = Collections.unmodifiableMap(new HashMap<FileFormat, String>() {{
|
|
||||||
put(FileFormat.PNG, "image/png");
|
|
||||||
put(FileFormat.SVG, "image/svg+xml");
|
|
||||||
put(FileFormat.EPS, "application/postscript");
|
|
||||||
put(FileFormat.UTXT, "text/plain;charset=UTF-8");
|
|
||||||
put(FileFormat.BASE64, "text/plain; charset=x-user-defined");
|
|
||||||
}});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -103,6 +113,42 @@ public class DiagramResponse {
|
|||||||
request = req;
|
request = req;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize PlantUML configurations and properties as well as loading the PlantUML config file.
|
||||||
|
*/
|
||||||
|
public static void init() {
|
||||||
|
if (initialized) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
initialized = true;
|
||||||
|
// set headless mode manually since otherwise Windows 11 seems to have some issues with it
|
||||||
|
// see Issue#311 :: https://github.com/plantuml/plantuml-server/issues/311
|
||||||
|
// NOTE: This can only be set before any awt/X11/... related stuff is loaded
|
||||||
|
System.setProperty("java.awt.headless", System.getProperty("java.awt.headless", "true"));
|
||||||
|
// set security profile to INTERNET by default
|
||||||
|
// NOTE: this property is cached inside PlantUML and cannot be changed after the first call of PlantUML
|
||||||
|
System.setProperty("PLANTUML_SECURITY_PROFILE", SecurityProfile.INTERNET.toString());
|
||||||
|
if (System.getenv("PLANTUML_SECURITY_PROFILE") != null) {
|
||||||
|
System.setProperty("PLANTUML_SECURITY_PROFILE", System.getenv("PLANTUML_SECURITY_PROFILE"));
|
||||||
|
}
|
||||||
|
// load properties from file
|
||||||
|
if (System.getenv("PLANTUML_PROPERTY_FILE") != null) {
|
||||||
|
try (FileReader propertyFileReader = new FileReader(System.getenv("PLANTUML_PROPERTY_FILE"))) {
|
||||||
|
System.getProperties().load(propertyFileReader);
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// load PlantUML config file
|
||||||
|
if (System.getenv("PLANTUML_CONFIG_FILE") != null) {
|
||||||
|
try (BufferedReader br = new BufferedReader(new FileReader(System.getenv("PLANTUML_CONFIG_FILE")))) {
|
||||||
|
br.lines().forEach(CONFIG::add);
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Render and send a specific uml diagram.
|
* Render and send a specific uml diagram.
|
||||||
*
|
*
|
||||||
@ -114,7 +160,17 @@ public class DiagramResponse {
|
|||||||
public void sendDiagram(String uml, int idx) throws IOException {
|
public void sendDiagram(String uml, int idx) throws IOException {
|
||||||
response.addHeader("Access-Control-Allow-Origin", "*");
|
response.addHeader("Access-Control-Allow-Origin", "*");
|
||||||
response.setContentType(getContentType());
|
response.setContentType(getContentType());
|
||||||
SourceStringReader reader = new SourceStringReader(uml);
|
|
||||||
|
if (idx < 0) {
|
||||||
|
response.sendError(HttpServletResponse.SC_BAD_REQUEST, String.format("Invalid diagram index: {0}", idx));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final SourceStringReader reader = getSourceStringReader(uml);
|
||||||
|
if (reader == null) {
|
||||||
|
response.sendError(HttpServletResponse.SC_BAD_REQUEST, "No UML diagram found");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (format == FileFormat.BASE64) {
|
if (format == FileFormat.BASE64) {
|
||||||
byte[] imageBytes;
|
byte[] imageBytes;
|
||||||
try (ByteArrayOutputStream outstream = new ByteArrayOutputStream()) {
|
try (ByteArrayOutputStream outstream = new ByteArrayOutputStream()) {
|
||||||
@ -126,20 +182,86 @@ public class DiagramResponse {
|
|||||||
response.getOutputStream().write(encodedBytes.getBytes());
|
response.getOutputStream().write(encodedBytes.getBytes());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
final BlockUml blockUml = reader.getBlocks().get(0);
|
|
||||||
if (notModified(blockUml)) {
|
final BlockSelection blockSelection = getOutputBlockSelection(reader, idx);
|
||||||
addHeaderForCache(blockUml);
|
if (blockSelection == null) {
|
||||||
|
response.sendError(HttpServletResponse.SC_BAD_REQUEST);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (notModified(blockSelection.block)) {
|
||||||
|
addHeaderForCache(blockSelection.block);
|
||||||
response.sendError(HttpServletResponse.SC_NOT_MODIFIED);
|
response.sendError(HttpServletResponse.SC_NOT_MODIFIED);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (StringUtils.isDiagramCacheable(uml)) {
|
if (StringUtils.isDiagramCacheable(uml)) {
|
||||||
addHeaderForCache(blockUml);
|
addHeaderForCache(blockSelection.block);
|
||||||
}
|
}
|
||||||
final Diagram diagram = blockUml.getDiagram();
|
final Diagram diagram = blockSelection.block.getDiagram();
|
||||||
if (diagram instanceof PSystemError) {
|
if (diagram instanceof PSystemError) {
|
||||||
response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
|
response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
|
||||||
}
|
}
|
||||||
diagram.exportDiagram(response.getOutputStream(), idx, new FileFormatOption(format));
|
diagram.exportDiagram(response.getOutputStream(), blockSelection.systemIdx, new FileFormatOption(format));
|
||||||
|
}
|
||||||
|
|
||||||
|
private BlockSelection getOutputBlockSelection(SourceStringReader reader, int numImage) {
|
||||||
|
if (numImage < 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
Collection<BlockUml> blocks = reader.getBlocks();
|
||||||
|
if (blocks.isEmpty()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (BlockUml b : blocks) {
|
||||||
|
final Diagram system = b.getDiagram();
|
||||||
|
final int nbInSystem = system.getNbImages();
|
||||||
|
if (numImage < nbInSystem) {
|
||||||
|
return new BlockSelection(b, numImage);
|
||||||
|
}
|
||||||
|
numImage -= nbInSystem;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private SourceStringReader getSourceStringReader(String uml) {
|
||||||
|
SourceStringReader reader = getSourceStringReaderWithConfig(uml);
|
||||||
|
if (reader.getBlocks().isEmpty()) {
|
||||||
|
uml = "@startuml\n" + uml + "\n@enduml";
|
||||||
|
reader = getSourceStringReaderWithConfig(uml);
|
||||||
|
if (reader.getBlocks().isEmpty()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return reader;
|
||||||
|
}
|
||||||
|
|
||||||
|
private SourceStringReader getSourceStringReaderWithConfig(String uml) {
|
||||||
|
final Defines defines = getPreProcDefines();
|
||||||
|
SourceStringReader reader = new SourceStringReader(defines, uml, CONFIG);
|
||||||
|
if (!CONFIG.isEmpty() && reader.getBlocks().get(0).getDiagram().getWarningOrError() != null) {
|
||||||
|
reader = new SourceStringReader(defines, uml);
|
||||||
|
}
|
||||||
|
return reader;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get PlantUML preprocessor defines.
|
||||||
|
*
|
||||||
|
* @return preprocessor defines
|
||||||
|
*/
|
||||||
|
private Defines getPreProcDefines() {
|
||||||
|
final Defines defines;
|
||||||
|
if (SecurityUtils.getSecurityProfile() == SecurityProfile.UNSECURE) {
|
||||||
|
// set dirpath to current dir but keep filename and filenameNoExtension undefined
|
||||||
|
defines = Defines.createWithFileName(new java.io.File("dummy.puml"));
|
||||||
|
defines.overrideFilename("");
|
||||||
|
} else {
|
||||||
|
defines = Defines.createEmpty();
|
||||||
|
}
|
||||||
|
return defines;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -171,18 +293,36 @@ public class DiagramResponse {
|
|||||||
* @throws IOException if an input or output exception occurred
|
* @throws IOException if an input or output exception occurred
|
||||||
*/
|
*/
|
||||||
public void sendMap(String uml, int idx) throws IOException {
|
public void sendMap(String uml, int idx) throws IOException {
|
||||||
if (idx < 0) {
|
response.addHeader("Access-Control-Allow-Origin", "*");
|
||||||
idx = 0;
|
|
||||||
}
|
|
||||||
response.setContentType(getContentType());
|
response.setContentType(getContentType());
|
||||||
SourceStringReader reader = new SourceStringReader(uml);
|
|
||||||
final BlockUml blockUml = reader.getBlocks().get(0);
|
if (idx < 0) {
|
||||||
if (StringUtils.isDiagramCacheable(uml)) {
|
response.sendError(HttpServletResponse.SC_BAD_REQUEST, String.format("Invalid diagram index: {0}", idx));
|
||||||
addHeaderForCache(blockUml);
|
return;
|
||||||
}
|
}
|
||||||
final Diagram diagram = blockUml.getDiagram();
|
final SourceStringReader reader = getSourceStringReader(uml);
|
||||||
ImageData map = diagram.exportDiagram(new NullOutputStream(), idx,
|
if (reader == null) {
|
||||||
new FileFormatOption(FileFormat.PNG, false));
|
response.sendError(HttpServletResponse.SC_BAD_REQUEST, "No UML diagram found");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final BlockSelection blockSelection = getOutputBlockSelection(reader, idx);
|
||||||
|
if (blockSelection == null) {
|
||||||
|
response.sendError(HttpServletResponse.SC_BAD_REQUEST);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (StringUtils.isDiagramCacheable(uml)) {
|
||||||
|
addHeaderForCache(blockSelection.block);
|
||||||
|
}
|
||||||
|
final Diagram diagram = blockSelection.block.getDiagram();
|
||||||
|
if (diagram instanceof PSystemError) {
|
||||||
|
response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
|
||||||
|
}
|
||||||
|
ImageData map = diagram.exportDiagram(
|
||||||
|
new NullOutputStream(),
|
||||||
|
blockSelection.systemIdx,
|
||||||
|
new FileFormatOption(FileFormat.PNG, false)
|
||||||
|
);
|
||||||
if (map.containsCMapData()) {
|
if (map.containsCMapData()) {
|
||||||
PrintWriter httpOut = response.getWriter();
|
PrintWriter httpOut = response.getWriter();
|
||||||
final String cmap = map.getCMapData("plantuml");
|
final String cmap = map.getCMapData("plantuml");
|
||||||
@ -253,7 +393,7 @@ public class DiagramResponse {
|
|||||||
* @return response content type
|
* @return response content type
|
||||||
*/
|
*/
|
||||||
private String getContentType() {
|
private String getContentType() {
|
||||||
return CONTENT_TYPE.get(format);
|
return format.getMimeType();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,376 @@
|
|||||||
|
/* ========================================================================
|
||||||
|
* PlantUML : a free UML diagram generator
|
||||||
|
* ========================================================================
|
||||||
|
*
|
||||||
|
* Project Info: https://plantuml.com
|
||||||
|
*
|
||||||
|
* This file is part of PlantUML.
|
||||||
|
*
|
||||||
|
* PlantUML is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* PlantUML distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||||
|
* License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
|
||||||
|
* USA.
|
||||||
|
*/
|
||||||
|
package net.sourceforge.plantuml.servlet;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.net.HttpURLConnection;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.nio.file.Paths;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import jakarta.servlet.ServletException;
|
||||||
|
import jakarta.servlet.annotation.MultipartConfig;
|
||||||
|
import jakarta.servlet.http.HttpServlet;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
import jakarta.servlet.http.Part;
|
||||||
|
import net.sourceforge.plantuml.FileFormat;
|
||||||
|
import net.sourceforge.plantuml.code.NoPlantumlCompressionException;
|
||||||
|
import net.sourceforge.plantuml.code.TranscoderUtil;
|
||||||
|
import net.sourceforge.plantuml.json.JsonObject;
|
||||||
|
import net.sourceforge.plantuml.klimt.drawing.svg.SvgGraphics;
|
||||||
|
import net.sourceforge.plantuml.png.MetadataTag;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Meta data servlet for the webapp.
|
||||||
|
* This servlet responses with the meta data of a specific file as text report or JSON object.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("SERIAL")
|
||||||
|
@MultipartConfig
|
||||||
|
public class MetadataServlet extends HttpServlet {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
|
||||||
|
request.setCharacterEncoding("UTF-8");
|
||||||
|
final String urlString = request.getParameter("src");
|
||||||
|
// validate URL
|
||||||
|
final URL url = ProxyServlet.validateURL(urlString, response);
|
||||||
|
if (url == null) {
|
||||||
|
return; // error is already set/handled inside `validateURL`
|
||||||
|
}
|
||||||
|
// fetch image via URL and extract meta data from it
|
||||||
|
final HttpURLConnection conn = ProxyServlet.getConnection(url);
|
||||||
|
try (InputStream is = conn.getInputStream()) {
|
||||||
|
handleRequest(request, response, is, conn.getContentType(), null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void doPost(
|
||||||
|
HttpServletRequest request,
|
||||||
|
HttpServletResponse response
|
||||||
|
) throws IOException, ServletException {
|
||||||
|
request.setCharacterEncoding("UTF-8");
|
||||||
|
// get image via file upload
|
||||||
|
final Part filePart = request.getPart("diagram");
|
||||||
|
final String filename = Paths.get(filePart.getSubmittedFileName()).getFileName().toString(); // MS IE fix
|
||||||
|
try (InputStream is = filePart.getInputStream()) {
|
||||||
|
handleRequest(request, response, is, null, filename);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle request no matter whether GET or POST and
|
||||||
|
* response with the PlantUML diagram image in the in the desired format if possible.
|
||||||
|
*
|
||||||
|
* @param request an HttpServletRequest object that contains the request the client has made of the servlet
|
||||||
|
* @param response an HttpServletResponse object that contains the response the servlet sends to the client
|
||||||
|
* @param is PlantUML diagram image as input stream
|
||||||
|
* @param contentType the PlantUML diagram image content type [optional]
|
||||||
|
* @param filename the PlantUML diagram image filename [optional
|
||||||
|
*
|
||||||
|
* @throws IOException if an input or output error is detected when the servlet handles the request
|
||||||
|
*/
|
||||||
|
private void handleRequest(
|
||||||
|
HttpServletRequest request,
|
||||||
|
HttpServletResponse response,
|
||||||
|
InputStream is,
|
||||||
|
String contentType,
|
||||||
|
String filename
|
||||||
|
) throws IOException {
|
||||||
|
final String formString = request.getParameter("format");
|
||||||
|
final String accept = request.getHeader("Accept");
|
||||||
|
final boolean isJsonResponse = accept != null && accept.toLowerCase().contains("json");
|
||||||
|
// extract meta data
|
||||||
|
// @see <a href="https://github.com/plantuml/plantuml/blob/26874fe610617738f958b7e8d012128fe621cff6/src/net/sourceforge/plantuml/Run.java#L570-L592">PlantUML Code</a>
|
||||||
|
final FileFormat format = getImageFileFormat(formString, contentType, filename, response);
|
||||||
|
if (format == null) {
|
||||||
|
return; // error is already set/handled inside `getImageFileFormat`
|
||||||
|
}
|
||||||
|
final Metadata metadata = getMetadata(is, format, response);
|
||||||
|
if (metadata == null) {
|
||||||
|
return; // error is already set/handled inside `getMetadata`
|
||||||
|
}
|
||||||
|
response.addHeader("Access-Control-Allow-Origin", "*");
|
||||||
|
if (isJsonResponse) {
|
||||||
|
response.setContentType("application/json;charset=UTF-8");
|
||||||
|
response.getWriter().write(metadata.toJson().toString());
|
||||||
|
} else {
|
||||||
|
response.setContentType(FileFormat.UTXT.getMimeType());
|
||||||
|
response.getWriter().write(metadata.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the file format from the PlantUML diagram image.
|
||||||
|
*
|
||||||
|
* @param format image format passed by the user via the request param `format`
|
||||||
|
* @param contentType response content type where the PlantUML diagram image is from
|
||||||
|
* @param filename diagram image file name
|
||||||
|
* @param response response object to `sendError` including error message
|
||||||
|
*
|
||||||
|
* @return PlantUML diagram image format; if unknown format return `null`
|
||||||
|
*
|
||||||
|
* @throws IOException `response.sendError` can result in a `IOException`
|
||||||
|
*/
|
||||||
|
private FileFormat getImageFileFormat(
|
||||||
|
String format, String contentType, String filename, HttpServletResponse response
|
||||||
|
) throws IOException {
|
||||||
|
if (format != null && !format.isEmpty()) {
|
||||||
|
return getImageFileFormatFromFormatString(format, response);
|
||||||
|
}
|
||||||
|
if (filename != null && !filename.isEmpty()) {
|
||||||
|
final FileFormat fileFormat = getImageFileFormatFromFilenameExtension(filename);
|
||||||
|
if (fileFormat != null) {
|
||||||
|
return fileFormat;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (contentType != null && !contentType.isEmpty()) {
|
||||||
|
final FileFormat fileFormat = getImageFileFormatFromContentType(contentType);
|
||||||
|
if (fileFormat != null) {
|
||||||
|
return fileFormat;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
response.sendError(
|
||||||
|
HttpServletResponse.SC_BAD_REQUEST,
|
||||||
|
"PlantUML image format detection failed. Please set \"format\" (format) manually."
|
||||||
|
);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the file format from the PlantUML diagram image based on a format string.
|
||||||
|
*
|
||||||
|
* @param format image format passed by the user via the request param `format`
|
||||||
|
* @param response response object to `sendError` including error message; if `null` no error will be send
|
||||||
|
*
|
||||||
|
* @return PlantUML diagram image format; if unknown format return `null`
|
||||||
|
*
|
||||||
|
* @throws IOException `response.sendError` can result in a `IOException`
|
||||||
|
*/
|
||||||
|
private FileFormat getImageFileFormatFromFormatString(
|
||||||
|
String format, HttpServletResponse response
|
||||||
|
) throws IOException {
|
||||||
|
switch (format.toLowerCase()) {
|
||||||
|
case "png": return FileFormat.PNG;
|
||||||
|
case "svg": return FileFormat.SVG;
|
||||||
|
default:
|
||||||
|
if (response != null) {
|
||||||
|
response.sendError(
|
||||||
|
HttpServletResponse.SC_BAD_REQUEST,
|
||||||
|
"The format \"" + format + "\" is not supported for meta data extraction."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the file format from the PlantUML diagram image based on the filenames extension.
|
||||||
|
*
|
||||||
|
* @param filename PlantUML image file name
|
||||||
|
*
|
||||||
|
* @return PlantUML diagram image format; if unknown format return `null`
|
||||||
|
*
|
||||||
|
* @throws IOException Can not happend! Will not occur.
|
||||||
|
*/
|
||||||
|
private FileFormat getImageFileFormatFromFilenameExtension(String filename) throws IOException {
|
||||||
|
int extensionPosition = filename.lastIndexOf(".");
|
||||||
|
if (extensionPosition != -1) {
|
||||||
|
String extension = filename.substring(extensionPosition + 1);
|
||||||
|
return getImageFileFormatFromFormatString(extension, null);
|
||||||
|
}
|
||||||
|
Logger logger = Logger.getLogger("com.plantuml");
|
||||||
|
logger.log(Level.WARNING, "File name \"{0}\" is malformed. Should be: name.extension", filename);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the file format from the PlantUML diagram image based on the response content type.
|
||||||
|
*
|
||||||
|
* @param contentType response content type where the PlantUML diagram image is from
|
||||||
|
*
|
||||||
|
* @return PlantUML diagram image format; if unknown content type return `null`
|
||||||
|
*/
|
||||||
|
private FileFormat getImageFileFormatFromContentType(String contentType) {
|
||||||
|
final String ct = contentType.toLowerCase();
|
||||||
|
if (ct.contains("png")) {
|
||||||
|
return FileFormat.PNG;
|
||||||
|
}
|
||||||
|
if (ct.contains("svg") || ct.contains("xml")) {
|
||||||
|
return FileFormat.SVG;
|
||||||
|
}
|
||||||
|
Logger logger = Logger.getLogger("com.plantuml");
|
||||||
|
logger.log(Level.SEVERE, "Unknown content type \"{0}\" for meta data extraction", contentType);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get meta data from PlantUML diagram image.
|
||||||
|
*
|
||||||
|
* @param is PlantUML diagram image input stream
|
||||||
|
* @param format PlantUML diagram image file format
|
||||||
|
* @param response response object to `sendError` including error message
|
||||||
|
*
|
||||||
|
* @return parsed meta data; on error return `null`
|
||||||
|
*
|
||||||
|
* @throws IOException `response.sendError` can result in a `IOException`
|
||||||
|
*/
|
||||||
|
private Metadata getMetadata(
|
||||||
|
InputStream is, FileFormat format, HttpServletResponse response
|
||||||
|
) throws IOException {
|
||||||
|
switch (format) {
|
||||||
|
case PNG:
|
||||||
|
return getMetadataFromPNG(is, response);
|
||||||
|
case SVG:
|
||||||
|
final String svg;
|
||||||
|
try (BufferedReader br = new BufferedReader(new InputStreamReader(is))) {
|
||||||
|
svg = br.lines().collect(Collectors.joining("\n"));
|
||||||
|
}
|
||||||
|
return getMetadataFromSVG(svg, response);
|
||||||
|
default:
|
||||||
|
response.sendError(HttpServletResponse.SC_BAD_REQUEST, "Unsupported image format.");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get meta data from PNG PlantUML diagram image.
|
||||||
|
*
|
||||||
|
* Challenge: PNG meta data is only a single String and contains more than the PlantUML diagram.
|
||||||
|
* PNG meta data contains:
|
||||||
|
* 1. decoded PlantUML code
|
||||||
|
* 2. empty line
|
||||||
|
* 3. version information
|
||||||
|
* Notes:
|
||||||
|
* - in theory the meta data could contain the PlantUML `RawString` as well as the `PlainString`
|
||||||
|
* but since both are ALWAYS identical (methods to get them are identical), one will ALWAYS dropped.
|
||||||
|
* @see <a href="https://github.com/plantuml/plantuml/blob/26874fe610617738f958b7e8d012128fe621cff6/src/net/sourceforge/plantuml/core/UmlSource.java#L173-L189">PlantUML Code</a>
|
||||||
|
* - version information do not contain any empty lines
|
||||||
|
* Solution: split meta data at the last occurring empty line the result in
|
||||||
|
* a. decoded PlantUML diagram
|
||||||
|
* b. version information
|
||||||
|
*
|
||||||
|
* @param is PNG image input stream
|
||||||
|
* @param response response object to `sendError` including error message
|
||||||
|
*
|
||||||
|
* @return parsed meta data; on error return `null`
|
||||||
|
*
|
||||||
|
* @throws IOException `response.sendError` can result in a `IOException`
|
||||||
|
*/
|
||||||
|
private Metadata getMetadataFromPNG(InputStream is, HttpServletResponse response) throws IOException {
|
||||||
|
final String rawMetadata = new MetadataTag(is, "plantuml").getData();
|
||||||
|
if (rawMetadata == null) {
|
||||||
|
response.sendError(HttpServletResponse.SC_BAD_REQUEST, "No meta data found.");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
// parse meta data
|
||||||
|
final Metadata metadata = new Metadata(rawMetadata.trim());
|
||||||
|
metadata.decoded = metadata.rawContent.substring(0, metadata.rawContent.lastIndexOf("\n\n"));
|
||||||
|
metadata.encoded = TranscoderUtil.getDefaultTranscoder().encode(metadata.decoded);
|
||||||
|
metadata.version = metadata.rawContent.substring(rawMetadata.lastIndexOf("\n\n")).trim();
|
||||||
|
// add additionally the encoded plantuml string to raw meta data since it's missing by default
|
||||||
|
metadata.rawContent = metadata.encoded + "\n\n" + metadata.rawContent;
|
||||||
|
return metadata;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get meta data from SVG PlantUML diagram image.
|
||||||
|
* @see <a href="https://github.com/plantuml/plantuml/blob/26874fe610617738f958b7e8d012128fe621cff6/src/net/sourceforge/plantuml/Run.java#L574-L587">PlantUML Code</a>
|
||||||
|
*
|
||||||
|
* @param svg PlantUML digram in SVG format
|
||||||
|
* @param response response object to `sendError` including error message
|
||||||
|
*
|
||||||
|
* @return parsed meta data; on error return `null`
|
||||||
|
*
|
||||||
|
* @throws IOException `response.sendError` can result in a `IOException`
|
||||||
|
*/
|
||||||
|
private Metadata getMetadataFromSVG(String svg, HttpServletResponse response) throws IOException {
|
||||||
|
final Metadata metadata = new Metadata();
|
||||||
|
// search for meta data start token
|
||||||
|
final int idx = svg.lastIndexOf(SvgGraphics.META_HEADER);
|
||||||
|
if (idx == -1) {
|
||||||
|
response.sendError(HttpServletResponse.SC_BAD_REQUEST, "No meta data found.");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
// search for meta data end token
|
||||||
|
final String part = svg.substring(idx + SvgGraphics.META_HEADER.length());
|
||||||
|
final int idxEnd = part.indexOf("]");
|
||||||
|
if (idxEnd == -1) {
|
||||||
|
response.sendError(HttpServletResponse.SC_BAD_REQUEST, "Invalid meta data: No end token found.");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
// parse meta data
|
||||||
|
metadata.encoded = part.substring(0, idxEnd);
|
||||||
|
try {
|
||||||
|
metadata.decoded = TranscoderUtil.getDefaultTranscoderProtected().decode(metadata.encoded);
|
||||||
|
} catch (NoPlantumlCompressionException ex) {
|
||||||
|
response.sendError(HttpServletResponse.SC_BAD_REQUEST, "Invalid meta data: PlantUML diagram is corrupted.");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return metadata;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper class to store meta data.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("checkstyle:VisibilityModifier")
|
||||||
|
private class Metadata {
|
||||||
|
public String rawContent;
|
||||||
|
public String decoded;
|
||||||
|
public String encoded;
|
||||||
|
public String version;
|
||||||
|
|
||||||
|
Metadata() { }
|
||||||
|
Metadata(String rawMetadataContent) {
|
||||||
|
rawContent = rawMetadataContent;
|
||||||
|
}
|
||||||
|
|
||||||
|
public JsonObject toJson() {
|
||||||
|
JsonObject metadata = new JsonObject();
|
||||||
|
metadata.add("encoded", encoded);
|
||||||
|
metadata.add("decoded", decoded);
|
||||||
|
if (version != null && !version.isEmpty()) {
|
||||||
|
metadata.add("version", version);
|
||||||
|
}
|
||||||
|
return metadata;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
if (rawContent != null && !rawContent.isEmpty()) {
|
||||||
|
return rawContent;
|
||||||
|
}
|
||||||
|
if (version == null || version.isEmpty()) {
|
||||||
|
return encoded + "\n\n" + decoded;
|
||||||
|
}
|
||||||
|
return encoded + "\n\n" + decoded + "\n\n" + version;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -51,7 +51,7 @@ public class OldProxyServlet extends HttpServlet {
|
|||||||
/**
|
/**
|
||||||
* Proxy request URI regex pattern.
|
* Proxy request URI regex pattern.
|
||||||
*/
|
*/
|
||||||
private static final Pattern PROXY_PATTERN = Pattern.compile("/\\w+/proxy/((\\d+)/)?((\\w+)/)?(https?://.*)");
|
private static final Pattern PROXY_PATTERN = Pattern.compile("/\\w+/proxy/((\\d+)/)?((\\w+)/)?(https?://[^@]*)");
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
|
public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
|
||||||
@ -61,13 +61,18 @@ public class OldProxyServlet extends HttpServlet {
|
|||||||
Matcher proxyMatcher = PROXY_PATTERN.matcher(uri);
|
Matcher proxyMatcher = PROXY_PATTERN.matcher(uri);
|
||||||
if (!proxyMatcher.matches()) {
|
if (!proxyMatcher.matches()) {
|
||||||
// Bad URI format.
|
// Bad URI format.
|
||||||
response.setStatus(400);
|
response.sendError(HttpServletResponse.SC_BAD_REQUEST, "URL malformed.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
String num = proxyMatcher.group(2); // Optional number of the diagram source
|
String num = proxyMatcher.group(2); // Optional number of the diagram source
|
||||||
String format = proxyMatcher.group(4); // Expected format of the generated diagram
|
String format = proxyMatcher.group(4); // Expected format of the generated diagram
|
||||||
String sourceURL = proxyMatcher.group(5);
|
String sourceURL = proxyMatcher.group(5);
|
||||||
|
if (ProxyServlet.forbiddenURL(sourceURL)) {
|
||||||
|
response.sendError(HttpServletResponse.SC_BAD_REQUEST, "Forbidden URL format.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
handleImageProxy(response, num, format, sourceURL);
|
handleImageProxy(response, num, format, sourceURL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,46 @@
|
|||||||
|
/* ========================================================================
|
||||||
|
* PlantUML : a free UML diagram generator
|
||||||
|
* ========================================================================
|
||||||
|
*
|
||||||
|
* Project Info: https://plantuml.com
|
||||||
|
*
|
||||||
|
* This file is part of PlantUML.
|
||||||
|
*
|
||||||
|
* PlantUML is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* PlantUML distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||||
|
* License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
|
||||||
|
* USA.
|
||||||
|
*/
|
||||||
|
package net.sourceforge.plantuml.servlet;
|
||||||
|
|
||||||
|
import net.sourceforge.plantuml.FileFormat;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PDF servlet of the webapp.
|
||||||
|
* This servlet produces the UML diagram in PDF format.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("SERIAL")
|
||||||
|
public class PdfServlet extends UmlDiagramService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gives the wished output format of the diagram.
|
||||||
|
* This value is used by the DiagramResponse class.
|
||||||
|
*
|
||||||
|
* @return the format for pdf responses
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public FileFormat getOutputFormat() {
|
||||||
|
return FileFormat.PDF;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -27,21 +27,15 @@ import java.io.IOException;
|
|||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.net.HttpURLConnection;
|
import java.net.HttpURLConnection;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.util.regex.Matcher;
|
|
||||||
import java.util.regex.Pattern;
|
|
||||||
|
|
||||||
import javax.net.ssl.HttpsURLConnection;
|
import javax.net.ssl.HttpsURLConnection;
|
||||||
|
|
||||||
import jakarta.servlet.RequestDispatcher;
|
import jakarta.servlet.RequestDispatcher;
|
||||||
import jakarta.servlet.ServletException;
|
import jakarta.servlet.ServletException;
|
||||||
import jakarta.servlet.http.HttpServlet;
|
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
import net.sourceforge.plantuml.OptionFlags;
|
|
||||||
import net.sourceforge.plantuml.api.PlantumlUtils;
|
import net.sourceforge.plantuml.api.PlantumlUtils;
|
||||||
import net.sourceforge.plantuml.code.Transcoder;
|
import net.sourceforge.plantuml.code.NoPlantumlCompressionException;
|
||||||
import net.sourceforge.plantuml.code.TranscoderUtil;
|
|
||||||
import net.sourceforge.plantuml.png.MetadataTag;
|
import net.sourceforge.plantuml.png.MetadataTag;
|
||||||
import net.sourceforge.plantuml.servlet.utility.Configuration;
|
import net.sourceforge.plantuml.servlet.utility.Configuration;
|
||||||
import net.sourceforge.plantuml.servlet.utility.UmlExtractor;
|
import net.sourceforge.plantuml.servlet.utility.UmlExtractor;
|
||||||
@ -58,7 +52,13 @@ import net.sourceforge.plantuml.servlet.utility.UrlDataExtractor;
|
|||||||
* Modified by Maxime Sinclair
|
* Modified by Maxime Sinclair
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("SERIAL")
|
@SuppressWarnings("SERIAL")
|
||||||
public class PlantUmlServlet extends HttpServlet {
|
public class PlantUmlServlet extends AsciiCoderServlet {
|
||||||
|
|
||||||
|
static {
|
||||||
|
// Initialize the PlantUML server.
|
||||||
|
// You could say that this is like the `static void main(String[] args)` of the PlantUML server.
|
||||||
|
DiagramResponse.init();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Default encoded uml text.
|
* Default encoded uml text.
|
||||||
@ -66,23 +66,24 @@ public class PlantUmlServlet extends HttpServlet {
|
|||||||
*/
|
*/
|
||||||
private static final String DEFAULT_ENCODED_TEXT = "SyfFKj2rKt3CoKnELR1Io4ZDoSa70000";
|
private static final String DEFAULT_ENCODED_TEXT = "SyfFKj2rKt3CoKnELR1Io4ZDoSa70000";
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getServletContextPath() {
|
||||||
|
return "uml";
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Regex pattern to fetch last part of the URL.
|
* Encode arbitrary string to HTML string.
|
||||||
|
*
|
||||||
|
* @param string arbitrary string
|
||||||
|
*
|
||||||
|
* @return html encoded string
|
||||||
*/
|
*/
|
||||||
private static final Pattern URL_PATTERN = Pattern.compile("^.*[^a-zA-Z0-9\\-\\_]([a-zA-Z0-9\\-\\_]+)");
|
|
||||||
|
|
||||||
static {
|
|
||||||
OptionFlags.ALLOW_INCLUDE = false;
|
|
||||||
if ("true".equalsIgnoreCase(System.getenv("ALLOW_PLANTUML_INCLUDE"))) {
|
|
||||||
OptionFlags.ALLOW_INCLUDE = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String stringToHTMLString(String string) {
|
public static String stringToHTMLString(String string) {
|
||||||
final StringBuffer sb = new StringBuffer(string.length());
|
final StringBuilder sb = new StringBuilder(string.length());
|
||||||
// true if last char was blank
|
// true if last char was blank
|
||||||
final int length = string.length();
|
final int length = string.length();
|
||||||
for (int offset = 0; offset < length;) {
|
int offset = 0;
|
||||||
|
while (offset < length) {
|
||||||
final int c = string.codePointAt(offset);
|
final int c = string.codePointAt(offset);
|
||||||
if (c == ' ') {
|
if (c == ' ') {
|
||||||
sb.append(' ');
|
sb.append(' ');
|
||||||
@ -115,7 +116,6 @@ public class PlantUmlServlet extends HttpServlet {
|
|||||||
return sb.toString();
|
return sb.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
|
public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
|
||||||
request.setCharacterEncoding("UTF-8");
|
request.setCharacterEncoding("UTF-8");
|
||||||
@ -133,8 +133,15 @@ public class PlantUmlServlet extends HttpServlet {
|
|||||||
final int idx = UrlDataExtractor.getIndex(request.getRequestURI());
|
final int idx = UrlDataExtractor.getIndex(request.getRequestURI());
|
||||||
|
|
||||||
// forward to index.jsp
|
// forward to index.jsp
|
||||||
|
final String path;
|
||||||
|
final String view = request.getParameter("view");
|
||||||
|
if (view != null && view.equalsIgnoreCase("previewer")) {
|
||||||
|
path = "/previewer.jsp";
|
||||||
|
} else {
|
||||||
|
path = "/index.jsp";
|
||||||
|
}
|
||||||
prepareRequestForDispatch(request, text, idx);
|
prepareRequestForDispatch(request, text, idx);
|
||||||
final RequestDispatcher dispatcher = request.getRequestDispatcher("/index.jsp");
|
final RequestDispatcher dispatcher = request.getRequestDispatcher(path);
|
||||||
dispatcher.forward(request, response);
|
dispatcher.forward(request, response);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -182,6 +189,10 @@ public class PlantUmlServlet extends HttpServlet {
|
|||||||
if (text != null && !text.isEmpty()) {
|
if (text != null && !text.isEmpty()) {
|
||||||
return text;
|
return text;
|
||||||
}
|
}
|
||||||
|
} catch (NoPlantumlCompressionException e) {
|
||||||
|
// no textual diagram source available from Url
|
||||||
|
// ignore and try 2. method (metadata) below
|
||||||
|
// do not spam output console
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
@ -215,26 +226,7 @@ public class PlantUmlServlet extends HttpServlet {
|
|||||||
* @throws IOException if an input or output exception occurred
|
* @throws IOException if an input or output exception occurred
|
||||||
*/
|
*/
|
||||||
private String getTextFromUrl(HttpServletRequest request) throws IOException {
|
private String getTextFromUrl(HttpServletRequest request) throws IOException {
|
||||||
// textual diagram source from request URI
|
return getTranscoder().decode(getEncodedTextFromUrl(request));
|
||||||
String url = request.getRequestURI();
|
|
||||||
if (url.contains("/uml/") && !url.endsWith("/uml/")) {
|
|
||||||
final String encoded = UrlDataExtractor.getEncodedDiagram(request.getRequestURI(), "");
|
|
||||||
if (!encoded.isEmpty()) {
|
|
||||||
return getTranscoder().decode(encoded);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// textual diagram source from "url" parameter
|
|
||||||
url = request.getParameter("url");
|
|
||||||
if (url != null && !url.trim().isEmpty()) {
|
|
||||||
// Catch the last part of the URL if necessary
|
|
||||||
final Matcher matcher = URL_PATTERN.matcher(url);
|
|
||||||
if (matcher.find()) {
|
|
||||||
url = matcher.group(1);
|
|
||||||
}
|
|
||||||
return getTranscoder().decode(url);
|
|
||||||
}
|
|
||||||
// nothing found
|
|
||||||
return "";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -247,28 +239,16 @@ public class PlantUmlServlet extends HttpServlet {
|
|||||||
*/
|
*/
|
||||||
private void prepareRequestForDispatch(HttpServletRequest request, String text, int idx) throws IOException {
|
private void prepareRequestForDispatch(HttpServletRequest request, String text, int idx) throws IOException {
|
||||||
final String encoded = getTranscoder().encode(text);
|
final String encoded = getTranscoder().encode(text);
|
||||||
final String index = (idx < 0) ? "" : idx + "/";
|
|
||||||
// diagram sources
|
// diagram sources
|
||||||
|
request.setAttribute("encoded", encoded);
|
||||||
request.setAttribute("decoded", text);
|
request.setAttribute("decoded", text);
|
||||||
request.setAttribute("index", idx);
|
request.setAttribute("index", (idx < 0) ? "" : idx);
|
||||||
// properties
|
// properties
|
||||||
request.setAttribute("showSocialButtons", Configuration.get("SHOW_SOCIAL_BUTTONS"));
|
request.setAttribute("showSocialButtons", Configuration.get("SHOW_SOCIAL_BUTTONS"));
|
||||||
request.setAttribute("showGithubRibbon", Configuration.get("SHOW_GITHUB_RIBBON"));
|
request.setAttribute("showGithubRibbon", Configuration.get("SHOW_GITHUB_RIBBON"));
|
||||||
// URL base
|
|
||||||
final String hostpath = getHostpath(request);
|
|
||||||
request.setAttribute("hostpath", hostpath);
|
|
||||||
// image URLs
|
|
||||||
final boolean hasImg = !text.isEmpty();
|
|
||||||
request.setAttribute("hasImg", hasImg);
|
|
||||||
request.setAttribute("imgurl", hostpath + "/png/" + index + encoded);
|
|
||||||
request.setAttribute("svgurl", hostpath + "/svg/" + index + encoded);
|
|
||||||
request.setAttribute("txturl", hostpath + "/txt/" + index + encoded);
|
|
||||||
request.setAttribute("mapurl", hostpath + "/map/" + index + encoded);
|
|
||||||
// map for diagram source if necessary
|
// map for diagram source if necessary
|
||||||
final boolean hasMap = PlantumlUtils.hasCMapData(text);
|
|
||||||
request.setAttribute("hasMap", hasMap);
|
|
||||||
String map = "";
|
String map = "";
|
||||||
if (hasMap) {
|
if (PlantumlUtils.hasCMapData(text)) {
|
||||||
try {
|
try {
|
||||||
map = UmlExtractor.extractMap(text);
|
map = UmlExtractor.extractMap(text);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
@ -278,33 +258,6 @@ public class PlantUmlServlet extends HttpServlet {
|
|||||||
request.setAttribute("map", map);
|
request.setAttribute("map", map);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Get hostpath (URL base) from request.
|
|
||||||
*
|
|
||||||
* @param request http request
|
|
||||||
*
|
|
||||||
* @return hostpath
|
|
||||||
*/
|
|
||||||
private String getHostpath(final HttpServletRequest request) {
|
|
||||||
// port
|
|
||||||
String port = "";
|
|
||||||
if (
|
|
||||||
(request.getScheme() == "http" && request.getServerPort() != 80)
|
|
||||||
||
|
|
||||||
(request.getScheme() == "https" && request.getServerPort() != 443)
|
|
||||||
) {
|
|
||||||
port = ":" + request.getServerPort();
|
|
||||||
}
|
|
||||||
// scheme
|
|
||||||
String scheme = request.getScheme();
|
|
||||||
final String forwardedProto = request.getHeader("x-forwarded-proto");
|
|
||||||
if (forwardedProto != null && !forwardedProto.isEmpty()) {
|
|
||||||
scheme = forwardedProto;
|
|
||||||
}
|
|
||||||
// hostpath
|
|
||||||
return scheme + "://" + request.getServerName() + port + request.getContextPath();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Send redirect response to encoded uml text.
|
* Send redirect response to encoded uml text.
|
||||||
*
|
*
|
||||||
@ -338,23 +291,13 @@ public class PlantUmlServlet extends HttpServlet {
|
|||||||
String encoded,
|
String encoded,
|
||||||
Integer index
|
Integer index
|
||||||
) throws IOException {
|
) throws IOException {
|
||||||
final String result;
|
final String path;
|
||||||
if (index == null || index < 0) {
|
if (index == null || index < 0) {
|
||||||
result = request.getContextPath() + "/uml/" + encoded;
|
path = request.getContextPath() + "/uml/" + encoded;
|
||||||
} else {
|
} else {
|
||||||
result = request.getContextPath() + "/uml/" + index + "/" + encoded;
|
path = request.getContextPath() + "/uml/" + index + "/" + encoded;
|
||||||
}
|
}
|
||||||
|
response.sendRedirect(path);
|
||||||
response.sendRedirect(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get PlantUML transcoder.
|
|
||||||
*
|
|
||||||
* @return transcoder instance
|
|
||||||
*/
|
|
||||||
private Transcoder getTranscoder() {
|
|
||||||
return TranscoderUtil.getDefaultTranscoder();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -371,7 +314,6 @@ public class PlantUmlServlet extends HttpServlet {
|
|||||||
HttpsURLConnection con = (HttpsURLConnection) url.openConnection();
|
HttpsURLConnection con = (HttpsURLConnection) url.openConnection();
|
||||||
con.setRequestMethod("GET");
|
con.setRequestMethod("GET");
|
||||||
con.setReadTimeout(10000); // 10 seconds
|
con.setReadTimeout(10000); // 10 seconds
|
||||||
// printHttpsCert(con);
|
|
||||||
con.connect();
|
con.connect();
|
||||||
return con;
|
return con;
|
||||||
} else {
|
} else {
|
||||||
|
@ -0,0 +1,202 @@
|
|||||||
|
/* ========================================================================
|
||||||
|
* PlantUML : a free UML diagram generator
|
||||||
|
* ========================================================================
|
||||||
|
*
|
||||||
|
* Project Info: https://plantuml.com
|
||||||
|
*
|
||||||
|
* This file is part of PlantUML.
|
||||||
|
*
|
||||||
|
* PlantUML is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* PlantUML distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||||
|
* License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
|
||||||
|
* USA.
|
||||||
|
*/
|
||||||
|
package net.sourceforge.plantuml.servlet;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.io.StringWriter;
|
||||||
|
import java.io.Writer;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import javax.xml.XMLConstants;
|
||||||
|
import javax.xml.parsers.DocumentBuilder;
|
||||||
|
import javax.xml.parsers.DocumentBuilderFactory;
|
||||||
|
import javax.xml.parsers.ParserConfigurationException;
|
||||||
|
import javax.xml.transform.OutputKeys;
|
||||||
|
import javax.xml.transform.Transformer;
|
||||||
|
import javax.xml.transform.TransformerException;
|
||||||
|
import javax.xml.transform.TransformerFactory;
|
||||||
|
import javax.xml.transform.dom.DOMSource;
|
||||||
|
import javax.xml.transform.stream.StreamResult;
|
||||||
|
|
||||||
|
import jakarta.servlet.ServletException;
|
||||||
|
import jakarta.servlet.http.HttpServlet;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
import net.sourceforge.plantuml.FileFormat;
|
||||||
|
import net.sourceforge.plantuml.emoji.data.Dummy;
|
||||||
|
import net.sourceforge.plantuml.json.Json;
|
||||||
|
import net.sourceforge.plantuml.json.JsonArray;
|
||||||
|
import net.sourceforge.plantuml.theme.ThemeUtils;
|
||||||
|
import net.sourceforge.plantuml.openiconic.data.DummyIcon;
|
||||||
|
|
||||||
|
import org.w3c.dom.Document;
|
||||||
|
import org.w3c.dom.NodeList;
|
||||||
|
import org.xml.sax.SAXException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Small PlantUML frontend or UI helper.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("SERIAL")
|
||||||
|
public class PlantUmlUIHelperServlet extends HttpServlet {
|
||||||
|
|
||||||
|
private interface HelperConsumer {
|
||||||
|
void accept(HttpServletRequest request, HttpServletResponse response) throws IOException;
|
||||||
|
}
|
||||||
|
|
||||||
|
private final Map<String, HelperConsumer> helpers = new HashMap<>();
|
||||||
|
private String svgIconsSpriteCache = null;
|
||||||
|
|
||||||
|
public PlantUmlUIHelperServlet() {
|
||||||
|
// add all supported request items/helper methods
|
||||||
|
helpers.put("emojis", this::sendEmojis);
|
||||||
|
helpers.put("icons.svg", this::sendIconsSprite);
|
||||||
|
helpers.put("icons", this::sendIcons);
|
||||||
|
helpers.put("themes", this::sendThemes);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
|
||||||
|
request.setCharacterEncoding("UTF-8");
|
||||||
|
|
||||||
|
final String requestItem = request.getParameter("request");
|
||||||
|
final HelperConsumer requestHelper = this.helpers.get(requestItem);
|
||||||
|
String errorMsg = null;
|
||||||
|
if (requestItem == null) {
|
||||||
|
errorMsg = "Request item not set.";
|
||||||
|
} else if (requestHelper == null) {
|
||||||
|
errorMsg = "Unknown requested item: " + requestItem;
|
||||||
|
}
|
||||||
|
if (errorMsg != null) {
|
||||||
|
setDefaultHeader(response, FileFormat.UTXT);
|
||||||
|
response.getWriter().write(errorMsg);
|
||||||
|
response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
requestHelper.accept(request, response);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setDefaultHeader(HttpServletResponse response, FileFormat fileFormat) {
|
||||||
|
setDefaultHeader(response, fileFormat.getMimeType());
|
||||||
|
}
|
||||||
|
|
||||||
|
private HttpServletResponse setDefaultHeader(HttpServletResponse response, String contentType) {
|
||||||
|
response.addHeader("Access-Control-Allow-Origin", "*");
|
||||||
|
response.setContentType(contentType);
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void sendJson(HttpServletResponse response, String json) throws IOException {
|
||||||
|
setDefaultHeader(response, "application/json;charset=UTF-8");
|
||||||
|
response.getWriter().write(json);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String[] getIcons() throws IOException {
|
||||||
|
InputStream in = DummyIcon.class.getResourceAsStream("all.txt");
|
||||||
|
try (BufferedReader br = new BufferedReader(new InputStreamReader(in))) {
|
||||||
|
return br.lines().toArray(String[]::new);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void sendIcons(HttpServletRequest request, HttpServletResponse response) throws IOException {
|
||||||
|
sendJson(response, Json.array(getIcons()).toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void sendIconsSprite(HttpServletRequest request, HttpServletResponse response) throws IOException {
|
||||||
|
if (svgIconsSpriteCache == null) {
|
||||||
|
// NOTE: all icons has the following svg tag attributes: width="8" height="8" viewBox="0 0 8 8"
|
||||||
|
String[] iconNames = getIcons();
|
||||||
|
StringBuilder sprite = new StringBuilder();
|
||||||
|
sprite.append("<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"8\" height=\"8\" viewBox=\"0 0 8 8\">\n");
|
||||||
|
sprite.append("<defs>\n");
|
||||||
|
sprite.append(" <style><![CDATA[\n");
|
||||||
|
sprite.append(" .sprite { display: none; }\n");
|
||||||
|
sprite.append(" .sprite:target { display: inline; }\n");
|
||||||
|
sprite.append(" ]]></style>\n");
|
||||||
|
sprite.append("</defs>\n");
|
||||||
|
for (String name : iconNames) {
|
||||||
|
try (InputStream in = DummyIcon.class.getResourceAsStream(name + ".svg")) {
|
||||||
|
DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
|
||||||
|
docFactory.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, "");
|
||||||
|
docFactory.setAttribute(XMLConstants.ACCESS_EXTERNAL_SCHEMA, "");
|
||||||
|
DocumentBuilder db = docFactory.newDocumentBuilder();
|
||||||
|
Document doc = db.parse(in);
|
||||||
|
|
||||||
|
Writer out = new StringWriter();
|
||||||
|
out.write("<g class=\"sprite\" id=\"" + name + "\">");
|
||||||
|
|
||||||
|
TransformerFactory tfFactory = TransformerFactory.newInstance();
|
||||||
|
tfFactory.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, "");
|
||||||
|
tfFactory.setAttribute(XMLConstants.ACCESS_EXTERNAL_STYLESHEET, "");
|
||||||
|
Transformer tf = tfFactory.newTransformer();
|
||||||
|
tf.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
|
||||||
|
tf.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
|
||||||
|
tf.setOutputProperty(OutputKeys.INDENT, "no");
|
||||||
|
NodeList svgInnerNodes = doc.getElementsByTagName("svg").item(0).getChildNodes();
|
||||||
|
for (int index = 0; index < svgInnerNodes.getLength(); index++) {
|
||||||
|
tf.transform(new DOMSource(svgInnerNodes.item(index)), new StreamResult(out));
|
||||||
|
}
|
||||||
|
|
||||||
|
out.write("</g>");
|
||||||
|
sprite.append(out.toString() + "\n");
|
||||||
|
} catch (ParserConfigurationException | SAXException | TransformerException ex) {
|
||||||
|
// skip icons which can not be parsed/read
|
||||||
|
Logger logger = Logger.getLogger("com.plantuml");
|
||||||
|
logger.log(Level.WARNING, "SVG icon \"{0}\" could not be parsed. Skip!", name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sprite.append("</svg>\n");
|
||||||
|
svgIconsSpriteCache = sprite.toString();
|
||||||
|
}
|
||||||
|
setDefaultHeader(response, FileFormat.SVG);
|
||||||
|
response.getWriter().write(svgIconsSpriteCache);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String[][] getEmojis() throws IOException {
|
||||||
|
InputStream in = Dummy.class.getResourceAsStream("emoji.txt");
|
||||||
|
try (BufferedReader br = new BufferedReader(new InputStreamReader(in))) {
|
||||||
|
return br.lines().map(line -> line.split(";")).toArray(String[][]::new);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void sendEmojis(HttpServletRequest request, HttpServletResponse response) throws IOException {
|
||||||
|
String[][] emojis = getEmojis();
|
||||||
|
JsonArray json = new JsonArray();
|
||||||
|
for (String[] emojiUnicodeNamePair : emojis) {
|
||||||
|
json.add(Json.array(emojiUnicodeNamePair));
|
||||||
|
}
|
||||||
|
sendJson(response, json.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void sendThemes(HttpServletRequest request, HttpServletResponse response) throws IOException {
|
||||||
|
String[] themes = ThemeUtils.getAllThemeNames().toArray(new String[0]);
|
||||||
|
sendJson(response, Json.array(themes).toString());
|
||||||
|
}
|
||||||
|
}
|
@ -29,24 +29,16 @@ import java.io.InputStreamReader;
|
|||||||
import java.net.HttpURLConnection;
|
import java.net.HttpURLConnection;
|
||||||
import java.net.MalformedURLException;
|
import java.net.MalformedURLException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.security.cert.Certificate;
|
import java.util.stream.Collectors;
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import javax.imageio.IIOException;
|
import javax.imageio.IIOException;
|
||||||
import javax.net.ssl.HttpsURLConnection;
|
|
||||||
import javax.net.ssl.SSLPeerUnverifiedException;
|
|
||||||
|
|
||||||
import jakarta.servlet.ServletException;
|
import jakarta.servlet.ServletException;
|
||||||
import jakarta.servlet.http.HttpServlet;
|
import jakarta.servlet.http.HttpServlet;
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
import net.sourceforge.plantuml.BlockUml;
|
|
||||||
import net.sourceforge.plantuml.FileFormat;
|
import net.sourceforge.plantuml.FileFormat;
|
||||||
import net.sourceforge.plantuml.OptionFlags;
|
|
||||||
import net.sourceforge.plantuml.SourceStringReader;
|
|
||||||
import net.sourceforge.plantuml.core.Diagram;
|
|
||||||
import net.sourceforge.plantuml.core.UmlSource;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Proxy servlet of the webapp.
|
* Proxy servlet of the webapp.
|
||||||
@ -56,49 +48,86 @@ import net.sourceforge.plantuml.core.UmlSource;
|
|||||||
@SuppressWarnings("SERIAL")
|
@SuppressWarnings("SERIAL")
|
||||||
public class ProxyServlet extends HttpServlet {
|
public class ProxyServlet extends HttpServlet {
|
||||||
|
|
||||||
static {
|
public static boolean forbiddenURL(String full) {
|
||||||
OptionFlags.ALLOW_INCLUDE = false;
|
if (full == null) {
|
||||||
if ("true".equalsIgnoreCase(System.getenv("ALLOW_PLANTUML_INCLUDE"))) {
|
return true;
|
||||||
OptionFlags.ALLOW_INCLUDE = true;
|
|
||||||
}
|
}
|
||||||
|
if (full.contains("@")) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (full.startsWith("https://") == false && full.startsWith("http://") == false) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (full.matches("^https?://[-#.0-9:\\[\\]+]+/.*")) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (full.matches("^https?://[^.]+/.*")) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (full.matches("^https?://[^.]+$")) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validate external URL.
|
||||||
|
*
|
||||||
|
* @param url URL to validate
|
||||||
|
* @param response response object to `sendError` including error message; if `null` no error will be send
|
||||||
|
*
|
||||||
|
* @return valid URL; otherwise `null`
|
||||||
|
*
|
||||||
|
* @throws IOException `response.sendError` can result in a `IOException`
|
||||||
|
*/
|
||||||
|
public static URL validateURL(String url, HttpServletResponse response) throws IOException {
|
||||||
|
final URL parsedUrl;
|
||||||
|
try {
|
||||||
|
parsedUrl = new URL(url);
|
||||||
|
} catch (MalformedURLException mue) {
|
||||||
|
if (response != null) {
|
||||||
|
response.sendError(HttpServletResponse.SC_BAD_REQUEST, "URL malformed.");
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
// Check if URL is in a forbidden format (e.g. IP-Address)
|
||||||
|
if (forbiddenURL(url)) {
|
||||||
|
if (response != null) {
|
||||||
|
response.sendError(HttpServletResponse.SC_BAD_REQUEST, "Forbidden URL format.");
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return parsedUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
|
public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
|
||||||
|
|
||||||
final String fmt = request.getParameter("fmt");
|
final String fmt = request.getParameter("fmt");
|
||||||
final String source = request.getParameter("src");
|
final String source = request.getParameter("src");
|
||||||
final String index = request.getParameter("idx");
|
final String index = request.getParameter("idx");
|
||||||
final URL srcUrl;
|
|
||||||
// Check if the src URL is valid
|
final int idx = index == null ? 0 : Integer.parseInt(index);
|
||||||
try {
|
final URL srcUrl = validateURL(source, response);
|
||||||
srcUrl = new URL(source);
|
if (srcUrl == null) {
|
||||||
} catch (MalformedURLException mue) {
|
return; // error is already set/handled inside `validateURL`
|
||||||
mue.printStackTrace();
|
|
||||||
response.setStatus(400);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// generate the response
|
// fetch diagram from URL
|
||||||
String diagmarkup = getSource(srcUrl);
|
final String uml = getSource(srcUrl);
|
||||||
SourceStringReader reader = new SourceStringReader(diagmarkup);
|
|
||||||
int n = index == null ? 0 : Integer.parseInt(index);
|
|
||||||
List<BlockUml> blocks = reader.getBlocks();
|
|
||||||
BlockUml block = blocks.get(n);
|
|
||||||
Diagram diagram = block.getDiagram();
|
|
||||||
UmlSource umlSrc = diagram.getSource();
|
|
||||||
String uml = umlSrc.getPlainString();
|
|
||||||
//System.out.println("uml=" + uml);
|
|
||||||
|
|
||||||
// generate the response
|
// generate the response
|
||||||
DiagramResponse dr = new DiagramResponse(response, getOutputFormat(fmt), request);
|
DiagramResponse dr = new DiagramResponse(response, getOutputFormat(fmt), request);
|
||||||
try {
|
try {
|
||||||
dr.sendDiagram(uml, 0);
|
// special handling for the MAP since it's not using "#sendDiagram()" like the other types
|
||||||
|
if ("map".equals(fmt)) {
|
||||||
|
dr.sendMap(uml, idx);
|
||||||
|
} else {
|
||||||
|
dr.sendDiagram(uml, idx);
|
||||||
|
}
|
||||||
} catch (IIOException e) {
|
} catch (IIOException e) {
|
||||||
// Browser has closed the connection, so the HTTP OutputStream is closed
|
// Browser has closed the connection, so the HTTP OutputStream is closed
|
||||||
// Silently catch the exception to avoid annoying log
|
// Silently catch the exception to avoid annoying log
|
||||||
}
|
}
|
||||||
dr = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -111,25 +140,10 @@ public class ProxyServlet extends HttpServlet {
|
|||||||
* @throws IOException if an input or output exception occurred
|
* @throws IOException if an input or output exception occurred
|
||||||
*/
|
*/
|
||||||
private String getSource(final URL url) throws IOException {
|
private String getSource(final URL url) throws IOException {
|
||||||
String line;
|
HttpURLConnection conn = getConnection(url);
|
||||||
BufferedReader rd;
|
try (BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream()))) {
|
||||||
StringBuilder sb;
|
return br.lines().collect(Collectors.joining("\n"));
|
||||||
try {
|
|
||||||
HttpURLConnection con = getConnection(url);
|
|
||||||
rd = new BufferedReader(new InputStreamReader(con.getInputStream()));
|
|
||||||
sb = new StringBuilder();
|
|
||||||
|
|
||||||
while ((line = rd.readLine()) != null) {
|
|
||||||
sb.append(line + '\n');
|
|
||||||
}
|
}
|
||||||
rd.close();
|
|
||||||
return sb.toString();
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
} finally {
|
|
||||||
rd = null;
|
|
||||||
}
|
|
||||||
return "";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -144,19 +158,16 @@ public class ProxyServlet extends HttpServlet {
|
|||||||
if (format == null) {
|
if (format == null) {
|
||||||
return FileFormat.PNG;
|
return FileFormat.PNG;
|
||||||
}
|
}
|
||||||
if (format.equals("svg")) {
|
switch (format.toLowerCase()) {
|
||||||
return FileFormat.SVG;
|
case "png": return FileFormat.PNG;
|
||||||
|
case "svg": return FileFormat.SVG;
|
||||||
|
case "eps": return FileFormat.EPS;
|
||||||
|
case "epstext": return FileFormat.EPS_TEXT;
|
||||||
|
case "txt": return FileFormat.UTXT;
|
||||||
|
case "map": return FileFormat.UTXT;
|
||||||
|
case "pdf": return FileFormat.PDF;
|
||||||
|
default: return FileFormat.PNG;
|
||||||
}
|
}
|
||||||
if (format.equals("eps")) {
|
|
||||||
return FileFormat.EPS;
|
|
||||||
}
|
|
||||||
if (format.equals("epstext")) {
|
|
||||||
return FileFormat.EPS_TEXT;
|
|
||||||
}
|
|
||||||
if (format.equals("txt")) {
|
|
||||||
return FileFormat.UTXT;
|
|
||||||
}
|
|
||||||
return FileFormat.PNG;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -168,48 +179,20 @@ public class ProxyServlet extends HttpServlet {
|
|||||||
*
|
*
|
||||||
* @throws IOException if an input or output exception occurred
|
* @throws IOException if an input or output exception occurred
|
||||||
*/
|
*/
|
||||||
private HttpURLConnection getConnection(final URL url) throws IOException {
|
public static HttpURLConnection getConnection(final URL url) throws IOException {
|
||||||
final HttpURLConnection con = (HttpURLConnection) url.openConnection();
|
final HttpURLConnection conn = (HttpURLConnection) url.openConnection();
|
||||||
//if (con instanceof HttpsURLConnection) {
|
conn.setRequestMethod("GET");
|
||||||
// printHttpsCert((HttpsURLConnection) con);
|
|
||||||
//}
|
|
||||||
con.setRequestMethod("GET");
|
|
||||||
String token = System.getenv("HTTP_AUTHORIZATION");
|
String token = System.getenv("HTTP_AUTHORIZATION");
|
||||||
if (token != null) {
|
if (token != null) {
|
||||||
con.setRequestProperty("Authorization", token);
|
conn.setRequestProperty("Authorization", token);
|
||||||
}
|
|
||||||
con.setReadTimeout(10000); // 10 seconds
|
|
||||||
con.connect();
|
|
||||||
return con;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Debug method used to dump the certificate info.
|
|
||||||
*
|
|
||||||
* @param con the https connection
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("unused")
|
|
||||||
private void printHttpsCert(final HttpsURLConnection con) {
|
|
||||||
if (con != null) {
|
|
||||||
try {
|
|
||||||
System.out.println("Response Code : " + con.getResponseCode());
|
|
||||||
System.out.println("Cipher Suite : " + con.getCipherSuite());
|
|
||||||
System.out.println("\n");
|
|
||||||
|
|
||||||
Certificate[] certs = con.getServerCertificates();
|
|
||||||
for (Certificate cert : certs) {
|
|
||||||
System.out.println("Cert Type : " + cert.getType());
|
|
||||||
System.out.println("Cert Hash Code : " + cert.hashCode());
|
|
||||||
System.out.println("Cert Public Key Algorithm : " + cert.getPublicKey().getAlgorithm());
|
|
||||||
System.out.println("Cert Public Key Format : " + cert.getPublicKey().getFormat());
|
|
||||||
System.out.println("\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
} catch (SSLPeerUnverifiedException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
}
|
||||||
|
final String timeoutString = System.getenv("HTTP_PROXY_READ_TIMEOUT");
|
||||||
|
int timeout = 10000; // 10 seconds as default
|
||||||
|
if (timeoutString != null && timeoutString.matches("^\\d+$")) {
|
||||||
|
timeout = Integer.parseInt(timeoutString);
|
||||||
}
|
}
|
||||||
|
conn.setReadTimeout(timeout);
|
||||||
|
conn.connect();
|
||||||
|
return conn;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -34,7 +34,6 @@ import jakarta.servlet.http.HttpServletRequest;
|
|||||||
import jakarta.servlet.http.HttpServletResponse;
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
import net.sourceforge.plantuml.FileFormat;
|
import net.sourceforge.plantuml.FileFormat;
|
||||||
import net.sourceforge.plantuml.OptionFlags;
|
|
||||||
import net.sourceforge.plantuml.servlet.utility.UmlExtractor;
|
import net.sourceforge.plantuml.servlet.utility.UmlExtractor;
|
||||||
import net.sourceforge.plantuml.servlet.utility.UrlDataExtractor;
|
import net.sourceforge.plantuml.servlet.utility.UrlDataExtractor;
|
||||||
|
|
||||||
@ -44,13 +43,6 @@ import net.sourceforge.plantuml.servlet.utility.UrlDataExtractor;
|
|||||||
@SuppressWarnings("SERIAL")
|
@SuppressWarnings("SERIAL")
|
||||||
public abstract class UmlDiagramService extends HttpServlet {
|
public abstract class UmlDiagramService extends HttpServlet {
|
||||||
|
|
||||||
static {
|
|
||||||
OptionFlags.ALLOW_INCLUDE = false;
|
|
||||||
if ("true".equalsIgnoreCase(System.getenv("ALLOW_PLANTUML_INCLUDE"))) {
|
|
||||||
OptionFlags.ALLOW_INCLUDE = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
|
public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
|
||||||
final String url = request.getRequestURI();
|
final String url = request.getRequestURI();
|
||||||
|
@ -29,7 +29,6 @@ import java.net.URLDecoder;
|
|||||||
|
|
||||||
import net.sourceforge.plantuml.FileFormat;
|
import net.sourceforge.plantuml.FileFormat;
|
||||||
import net.sourceforge.plantuml.FileFormatOption;
|
import net.sourceforge.plantuml.FileFormatOption;
|
||||||
import net.sourceforge.plantuml.OptionFlags;
|
|
||||||
import net.sourceforge.plantuml.SourceStringReader;
|
import net.sourceforge.plantuml.SourceStringReader;
|
||||||
import net.sourceforge.plantuml.code.Transcoder;
|
import net.sourceforge.plantuml.code.Transcoder;
|
||||||
import net.sourceforge.plantuml.code.TranscoderUtil;
|
import net.sourceforge.plantuml.code.TranscoderUtil;
|
||||||
@ -42,13 +41,6 @@ import net.sourceforge.plantuml.core.ImageData;
|
|||||||
*/
|
*/
|
||||||
public abstract class UmlExtractor {
|
public abstract class UmlExtractor {
|
||||||
|
|
||||||
static {
|
|
||||||
OptionFlags.ALLOW_INCLUDE = false;
|
|
||||||
if ("true".equalsIgnoreCase(System.getenv("ALLOW_PLANTUML_INCLUDE"))) {
|
|
||||||
OptionFlags.ALLOW_INCLUDE = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Build the complete UML source from the compressed source extracted from the
|
* Build the complete UML source from the compressed source extracted from the
|
||||||
* HTTP URI.
|
* HTTP URI.
|
||||||
|
@ -60,17 +60,18 @@
|
|||||||
<servlet-class>org.eclipse.jetty.jsp.JettyJspServlet</servlet-class>
|
<servlet-class>org.eclipse.jetty.jsp.JettyJspServlet</servlet-class>
|
||||||
<init-param>
|
<init-param>
|
||||||
<param-name>compilerSourceVM</param-name>
|
<param-name>compilerSourceVM</param-name>
|
||||||
<param-value>1.7</param-value>
|
<param-value>1.8</param-value>
|
||||||
</init-param>
|
</init-param>
|
||||||
<init-param>
|
<init-param>
|
||||||
<param-name>compilerTargetVM</param-name>
|
<param-name>compilerTargetVM</param-name>
|
||||||
<param-value>1.7</param-value>
|
<param-value>1.8</param-value>
|
||||||
</init-param>
|
</init-param>
|
||||||
</servlet>
|
</servlet>
|
||||||
|
|
||||||
<servlet>
|
<servlet>
|
||||||
<servlet-name>plantumlservlet</servlet-name>
|
<servlet-name>plantumlservlet</servlet-name>
|
||||||
<servlet-class>net.sourceforge.plantuml.servlet.PlantUmlServlet</servlet-class>
|
<servlet-class>net.sourceforge.plantuml.servlet.PlantUmlServlet</servlet-class>
|
||||||
|
<load-on-startup>0</load-on-startup>
|
||||||
</servlet>
|
</servlet>
|
||||||
<servlet-mapping>
|
<servlet-mapping>
|
||||||
<servlet-name>plantumlservlet</servlet-name>
|
<servlet-name>plantumlservlet</servlet-name>
|
||||||
@ -111,6 +112,15 @@
|
|||||||
<url-pattern>/svg/*</url-pattern>
|
<url-pattern>/svg/*</url-pattern>
|
||||||
</servlet-mapping>
|
</servlet-mapping>
|
||||||
|
|
||||||
|
<servlet>
|
||||||
|
<servlet-name>pdfservlet</servlet-name>
|
||||||
|
<servlet-class>net.sourceforge.plantuml.servlet.PdfServlet</servlet-class>
|
||||||
|
</servlet>
|
||||||
|
<servlet-mapping>
|
||||||
|
<servlet-name>pdfservlet</servlet-name>
|
||||||
|
<url-pattern>/pdf/*</url-pattern>
|
||||||
|
</servlet-mapping>
|
||||||
|
|
||||||
<servlet>
|
<servlet>
|
||||||
<servlet-name>epsservlet</servlet-name>
|
<servlet-name>epsservlet</servlet-name>
|
||||||
<servlet-class>net.sourceforge.plantuml.servlet.EpsServlet</servlet-class>
|
<servlet-class>net.sourceforge.plantuml.servlet.EpsServlet</servlet-class>
|
||||||
@ -192,6 +202,32 @@
|
|||||||
<url-pattern>/language</url-pattern>
|
<url-pattern>/language</url-pattern>
|
||||||
</servlet-mapping>
|
</servlet-mapping>
|
||||||
|
|
||||||
|
<servlet>
|
||||||
|
<servlet-name>asciicoderservlet</servlet-name>
|
||||||
|
<servlet-class>net.sourceforge.plantuml.servlet.AsciiCoderServlet</servlet-class>
|
||||||
|
</servlet>
|
||||||
|
<servlet-mapping>
|
||||||
|
<servlet-name>asciicoderservlet</servlet-name>
|
||||||
|
<url-pattern>/coder/*</url-pattern>
|
||||||
|
</servlet-mapping>
|
||||||
|
|
||||||
|
<servlet>
|
||||||
|
<servlet-name>plantumluihelperservlet</servlet-name>
|
||||||
|
<servlet-class>net.sourceforge.plantuml.servlet.PlantUmlUIHelperServlet</servlet-class>
|
||||||
|
</servlet>
|
||||||
|
<servlet-mapping>
|
||||||
|
<servlet-name>plantumluihelperservlet</servlet-name>
|
||||||
|
<url-pattern>/ui-helper/*</url-pattern>
|
||||||
|
</servlet-mapping>
|
||||||
|
|
||||||
|
<servlet>
|
||||||
|
<servlet-name>metadataservlet</servlet-name>
|
||||||
|
<servlet-class>net.sourceforge.plantuml.servlet.MetadataServlet</servlet-class>
|
||||||
|
</servlet>
|
||||||
|
<servlet-mapping>
|
||||||
|
<servlet-name>metadataservlet</servlet-name>
|
||||||
|
<url-pattern>/metadata/*</url-pattern>
|
||||||
|
</servlet-mapping>
|
||||||
|
|
||||||
<!-- ========================================================== -->
|
<!-- ========================================================== -->
|
||||||
<!-- Error Handler -->
|
<!-- Error Handler -->
|
||||||
|
1
src/main/webapp/assets/actions/copy.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg height="24" width="24" xmlns="http://www.w3.org/2000/svg"><path d="M16 16v4c0 1.152-.848 2-2 2H4c-1.152 0-2-.848-2-2V10c0-1.152.848-2 2-2h4V4c0-1.152.848-2 2-2h10c1.152 0 2 .848 2 2v10c0 1.152-.848 2-2 2h-4zm-2 0h-4c-1.152 0-2-.848-2-2v-4H4v10h10v-4zM10 4v10h10V4H10z" fill-rule="evenodd"/></svg>
|
After Width: | Height: | Size: 301 B |
1
src/main/webapp/assets/actions/dock.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg height="512" width="512" xmlns="http://www.w3.org/2000/svg"><path d="M384 224v184a40 40 0 01-40 40H104a40 40 0 01-40-40V168a40 40 0 0140-40h167.48" fill="none" stroke="#000" stroke-linecap="round" stroke-linejoin="round" stroke-width="32"/><path fill="none" stroke="#000" stroke-linecap="round" stroke-linejoin="round" stroke-width="32" d="M216 184v112h112m-104-8L440 72"/></svg>
|
After Width: | Height: | Size: 384 B |
1
src/main/webapp/assets/actions/download.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg fill="none" height="24" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" width="24" xmlns="http://www.w3.org/2000/svg"><path d="M21 15v4a2 2 0 01-2 2H5a2 2 0 01-2-2v-4M7 10l5 5 5-5M12 15V3"/></svg>
|
After Width: | Height: | Size: 240 B |
1
src/main/webapp/assets/actions/settings.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg height="512" width="512" xmlns="http://www.w3.org/2000/svg"><path d="M262.29 192.31a64 64 0 1057.4 57.4 64.13 64.13 0 00-57.4-57.4zM416.39 256a154.34 154.34 0 01-1.53 20.79l45.21 35.46a10.81 10.81 0 012.45 13.75l-42.77 74a10.81 10.81 0 01-13.14 4.59l-44.9-18.08a16.11 16.11 0 00-15.17 1.75A164.48 164.48 0 01325 400.8a15.94 15.94 0 00-8.82 12.14l-6.73 47.89a11.08 11.08 0 01-10.68 9.17h-85.54a11.11 11.11 0 01-10.69-8.87l-6.72-47.82a16.07 16.07 0 00-9-12.22 155.3 155.3 0 01-21.46-12.57 16 16 0 00-15.11-1.71l-44.89 18.07a10.81 10.81 0 01-13.14-4.58l-42.77-74a10.8 10.8 0 012.45-13.75l38.21-30a16.05 16.05 0 006-14.08c-.36-4.17-.58-8.33-.58-12.5s.21-8.27.58-12.35a16 16 0 00-6.07-13.94l-38.19-30A10.81 10.81 0 0149.48 186l42.77-74a10.81 10.81 0 0113.14-4.59l44.9 18.08a16.11 16.11 0 0015.17-1.75A164.48 164.48 0 01187 111.2a15.94 15.94 0 008.82-12.14l6.73-47.89A11.08 11.08 0 01213.23 42h85.54a11.11 11.11 0 0110.69 8.87l6.72 47.82a16.07 16.07 0 009 12.22 155.3 155.3 0 0121.46 12.57 16 16 0 0015.11 1.71l44.89-18.07a10.81 10.81 0 0113.14 4.58l42.77 74a10.8 10.8 0 01-2.45 13.75l-38.21 30a16.05 16.05 0 00-6.05 14.08c.33 4.14.55 8.3.55 12.47z" fill="none" stroke="#000" stroke-linecap="round" stroke-linejoin="round" stroke-width="32"/></svg>
|
After Width: | Height: | Size: 1.2 KiB |
1
src/main/webapp/assets/actions/undock.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg height="512" width="512" xmlns="http://www.w3.org/2000/svg"><path d="M384 224v184a40 40 0 01-40 40H104a40 40 0 01-40-40V168a40 40 0 0140-40h167.48M336 64h112v112M224 288L440 72" fill="none" stroke="#000" stroke-linecap="round" stroke-linejoin="round" stroke-width="32"/></svg>
|
After Width: | Height: | Size: 281 B |
1
src/main/webapp/assets/actions/upload.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg fill="none" height="24" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" width="24" xmlns="http://www.w3.org/2000/svg"><path d="M21 15v4a2 2 0 01-2 2H5a2 2 0 01-2-2v-4M17 8l-5-5-5 5M12 3v12"/></svg>
|
After Width: | Height: | Size: 241 B |
1
src/main/webapp/assets/file-types/ascii.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg class="bi bi-filetype-ascii" fill="currentColor" height="16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="M14 4.5V11h-1V4.5h-2A1.5 1.5 0 019.5 3V1H4a1 1 0 00-1 1v9H2V2a2 2 0 012-2h5.5zM2.404 14.903l-.313 1.028h-.8l1.342-3.999h.926l1.335 4h-.84l-.314-1.03H2.404zm1.178-.59l-.49-1.616h-.034l-.49 1.617h1.014zm1.782.977a1.178 1.178 0 01-.111-.449h.764a.58.58 0 00.255.384c.07.049.154.087.25.114.095.028.2.041.319.041.164 0 .3-.023.413-.07a.558.558 0 00.255-.193.507.507 0 00.085-.29.387.387 0 00-.153-.326c-.101-.08-.256-.144-.463-.193l-.618-.143a1.72 1.72 0 01-.54-.214 1.002 1.002 0 01-.35-.367 1.068 1.068 0 01-.123-.524c0-.244.063-.457.19-.639.127-.181.303-.322.527-.422.225-.1.484-.149.777-.149.304 0 .564.05.779.152.217.102.384.239.5.41.12.17.186.359.2.566h-.75a.56.56 0 00-.12-.258.623.623 0 00-.246-.181.923.923 0 00-.37-.068c-.216 0-.387.05-.512.152a.472.472 0 00-.184.384c0 .121.047.22.143.3a.97.97 0 00.404.175l.62.143c.218.05.407.12.567.211.16.09.285.21.375.358.09.148.135.335.135.56 0 .247-.063.466-.188.656-.133.196-.32.348-.54.439-.233.105-.52.158-.857.158a2.191 2.191 0 01-.665-.09 1.404 1.404 0 01-.478-.252 1.131 1.131 0 01-.29-.375zm4.383-2.246a1.732 1.732 0 00-.103.633v.495c0 .246.035.455.103.627a.834.834 0 00.299.393c.142.09.308.136.477.13a.872.872 0 00.402-.087.699.699 0 00.272-.248.8.8 0 00.117-.364h.765v.076c-.01.241-.088.475-.226.674-.136.194-.32.345-.55.454a1.81 1.81 0 01-.785.164c-.36 0-.665-.072-.915-.216a1.424 1.424 0 01-.57-.627c-.13-.272-.194-.597-.194-.976v-.498c0-.38.065-.705.196-.978.13-.274.32-.485.57-.633.253-.15.557-.223.913-.223.218 0 .42.032.606.097.187.062.35.153.49.272.283.241.452.591.465.964v.073h-.765a.85.85 0 00-.12-.38.7.7 0 00-.272-.261.802.802 0 00-.4-.097.814.814 0 00-.473.138.868.868 0 00-.302.398zm3.628-1.106v4h-.79v-4h.79zm1.337.005v3.999h-.791v-4h.79z" fill-rule="evenodd"/></svg>
|
After Width: | Height: | Size: 1.8 KiB |
1
src/main/webapp/assets/file-types/map.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg class="bi bi-filetype-map" fill="currentColor" height="16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="M14 4.5V14a2 2 0 01-2 2v-1a1 1 0 001-1V4.5h-2A1.5 1.5 0 019.5 3V1H4a1 1 0 00-1 1v9H2V2a2 2 0 012-2h5.5zM.706 15.849v-2.66h.038l.952 2.16h.516l.946-2.16h.038v2.66h.715V11.85h-.8l-1.14 2.596h-.026L.805 11.85H0v3.999zm7.31-3.999h1.6c.289 0 .533.06.732.179.201.117.355.276.46.477.106.201.158.427.158.677 0 .25-.053.476-.16.677-.106.199-.26.357-.464.474a1.46 1.46 0 01-.732.173h-.803v1.342h-.79V11.85zm2.06 1.714a.795.795 0 00.085-.381c0-.226-.062-.4-.185-.521-.123-.122-.294-.182-.513-.182h-.659v1.406h.66a.794.794 0 00.374-.082.574.574 0 00.238-.24zm-5.12 2.306l.313-1.028h1.336l.314 1.028h.84l-1.336-3.999h-.925l-1.329 3.96m1.79-3.195l.488 1.617H5.433l.49-1.617z" fill-rule="evenodd"/></svg>
|
After Width: | Height: | Size: 808 B |
1
src/main/webapp/assets/file-types/pdf.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg class="bi bi-filetype-pdf" fill="currentColor" height="16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="M14 4.5V14a2 2 0 01-2 2h-1v-1h1a1 1 0 001-1V4.5h-2A1.5 1.5 0 019.5 3V1H4a1 1 0 00-1 1v9H2V2a2 2 0 012-2h5.5L14 4.5zM1.6 11.85H0v3.999h.791v-1.342h.803c.287 0 .531-.057.732-.173.203-.117.358-.275.463-.474a1.42 1.42 0 00.161-.677c0-.25-.053-.476-.158-.677a1.176 1.176 0 00-.46-.477c-.2-.12-.443-.179-.732-.179zm.545 1.333a.795.795 0 01-.085.38.574.574 0 01-.238.241.794.794 0 01-.375.082H.788V12.48h.66c.218 0 .389.06.512.181.123.122.185.296.185.522zm1.217-1.333v3.999h1.46c.401 0 .734-.08.998-.237a1.45 1.45 0 00.595-.689c.13-.3.196-.662.196-1.084 0-.42-.065-.778-.196-1.075a1.426 1.426 0 00-.589-.68c-.264-.156-.599-.234-1.005-.234H3.362zm.791.645h.563c.248 0 .45.05.609.152a.89.89 0 01.354.454c.079.201.118.452.118.753a2.3 2.3 0 01-.068.592 1.14 1.14 0 01-.196.422.8.8 0 01-.334.252 1.298 1.298 0 01-.483.082h-.563v-2.707zm3.743 1.763v1.591h-.79V11.85h2.548v.653H7.896v1.117h1.606v.638H7.896z" fill-rule="evenodd"/></svg>
|
After Width: | Height: | Size: 1.0 KiB |
1
src/main/webapp/assets/file-types/png.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg class="bi bi-filetype-png" fill="currentColor" height="16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="M14 4.5V14a2 2 0 01-2 2v-1a1 1 0 001-1V4.5h-2A1.5 1.5 0 019.5 3V1H4a1 1 0 00-1 1v9H2V2a2 2 0 012-2h5.5L14 4.5zm-3.76 8.132c.076.153.123.317.14.492h-.776a.797.797 0 00-.097-.249.689.689 0 00-.17-.19.707.707 0 00-.237-.126.96.96 0 00-.299-.044c-.285 0-.506.1-.665.302-.156.201-.234.484-.234.85v.498c0 .234.032.439.097.615a.881.881 0 00.304.413.87.87 0 00.519.146.967.967 0 00.457-.096.67.67 0 00.272-.264c.06-.11.091-.23.091-.363v-.255H8.82v-.59h1.576v.798c0 .193-.032.377-.097.55a1.29 1.29 0 01-.293.458 1.37 1.37 0 01-.495.313c-.197.074-.43.111-.697.111a1.98 1.98 0 01-.753-.132 1.447 1.447 0 01-.533-.377 1.58 1.58 0 01-.32-.58 2.482 2.482 0 01-.105-.745v-.506c0-.362.067-.678.2-.95.134-.271.328-.482.582-.633.256-.152.565-.228.926-.228.238 0 .45.033.636.1.187.066.348.158.48.275.133.117.238.253.314.407zm-8.64-.706H0v4h.791v-1.343h.803c.287 0 .531-.057.732-.172.203-.118.358-.276.463-.475a1.42 1.42 0 00.161-.677c0-.25-.053-.475-.158-.677a1.176 1.176 0 00-.46-.477c-.2-.12-.443-.179-.732-.179zm.545 1.333a.795.795 0 01-.085.381.574.574 0 01-.238.24.794.794 0 01-.375.082H.788v-1.406h.66c.218 0 .389.06.512.182.123.12.185.295.185.521zm1.964 2.666V13.25h.032l1.761 2.675h.656v-3.999h-.75v2.66h-.032l-1.752-2.66h-.662v4h.747z" fill-rule="evenodd"/></svg>
|
After Width: | Height: | Size: 1.3 KiB |
1
src/main/webapp/assets/file-types/svg.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg class="bi bi-filetype-svg" fill="currentColor" height="16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="M14 4.5V14a2 2 0 01-2 2v-1a1 1 0 001-1V4.5h-2A1.5 1.5 0 019.5 3V1H4a1 1 0 00-1 1v9H2V2a2 2 0 012-2h5.5L14 4.5zM0 14.841a1.13 1.13 0 00.401.823c.13.108.288.192.478.252.19.061.411.091.665.091.338 0 .624-.053.858-.158.237-.105.416-.252.54-.44a1.17 1.17 0 00.187-.656c0-.224-.045-.41-.135-.56a1 1 0 00-.375-.357 2.027 2.027 0 00-.565-.21l-.621-.144a.97.97 0 01-.405-.176.37.37 0 01-.143-.299c0-.156.061-.284.184-.384.125-.101.296-.152.513-.152.143 0 .266.023.37.068a.625.625 0 01.245.181.56.56 0 01.12.258h.75a1.092 1.092 0 00-.199-.566 1.21 1.21 0 00-.5-.41 1.813 1.813 0 00-.78-.152c-.293 0-.552.05-.776.15-.225.099-.4.24-.528.421-.127.182-.19.395-.19.639 0 .201.04.376.123.524.082.149.199.27.351.367.153.095.332.167.54.213l.618.144c.207.049.36.113.462.193a.387.387 0 01.153.326.512.512 0 01-.085.29.559.559 0 01-.256.193c-.111.047-.249.07-.413.07-.117 0-.224-.013-.32-.04a.837.837 0 01-.248-.115.578.578 0 01-.255-.384H0zm4.575 1.09h.952l1.327-3.999h-.879l-.887 3.138H5.05l-.897-3.138h-.917l1.339 4zm5.483-3.293c.076.152.123.316.14.492h-.776a.797.797 0 00-.096-.249.689.689 0 00-.17-.19.707.707 0 00-.237-.126.963.963 0 00-.3-.044c-.284 0-.506.1-.664.302-.157.2-.235.484-.235.85v.497c0 .235.033.44.097.616a.881.881 0 00.305.413.87.87 0 00.518.146.965.965 0 00.457-.097.67.67 0 00.273-.263c.06-.11.09-.23.09-.364v-.254h-.823v-.59h1.576v.798c0 .193-.032.377-.096.55a1.29 1.29 0 01-.293.457 1.37 1.37 0 01-.495.314c-.198.074-.43.111-.698.111a1.98 1.98 0 01-.752-.132 1.447 1.447 0 01-.534-.377 1.58 1.58 0 01-.319-.58 2.482 2.482 0 01-.105-.745v-.507c0-.36.066-.677.199-.949.134-.271.329-.482.583-.633.256-.152.564-.228.926-.228.238 0 .45.033.635.1.188.066.348.158.48.275.134.117.238.253.314.407z" fill-rule="evenodd"/></svg>
|
After Width: | Height: | Size: 1.8 KiB |
1
src/main/webapp/assets/file-types/txt.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg class="bi bi-filetype-txt" fill="currentColor" height="16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="M14 4.5V14a2 2 0 01-2 2h-2v-1h2a1 1 0 001-1V4.5h-2A1.5 1.5 0 019.5 3V1H4a1 1 0 00-1 1v9H2V2a2 2 0 012-2h5.5L14 4.5zM1.928 15.849v-3.337h1.136v-.662H0v.662h1.134v3.337h.794zm4.689-3.999h-.894L4.9 13.289h-.035l-.832-1.439h-.932l1.228 1.983-1.24 2.016h.862l.853-1.415h.035l.85 1.415h.907l-1.253-1.992 1.274-2.007zm1.93.662v3.337h-.794v-3.337H6.619v-.662h3.064v.662H8.546z" fill-rule="evenodd"/></svg>
|
After Width: | Height: | Size: 516 B |
2
src/main/webapp/assets/github-fork-me.svg
Normal file
After Width: | Height: | Size: 6.7 KiB |
14
src/main/webapp/components/app-head.jsp
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
<base href="<%= request.getContextPath() %>/" />
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||||
|
<meta http-equiv="expires" content="0" />
|
||||||
|
<meta http-equiv="pragma" content="no-cache" />
|
||||||
|
<meta http-equiv="cache-control" content="no-cache, must-revalidate" />
|
||||||
|
<meta name="viewport" content="initial-scale=1.0, user-scalable=1" />
|
||||||
|
<meta name="color-scheme" content="light dark" />
|
||||||
|
<link rel="icon" href="favicon.ico" type="image/x-icon"/>
|
||||||
|
<link rel="shortcut icon" href="favicon.ico" type="image/x-icon"/>
|
||||||
|
<link rel="stylesheet" href="min/plantuml.min.css" />
|
||||||
|
<script src="min/plantuml.min.js"></script>
|
||||||
|
<script src="min/plantuml-language.min.js"></script>
|
||||||
|
<script src="webjars/monaco-editor/0.36.1/min/vs/loader.js"></script>
|
165
src/main/webapp/components/app.css
Normal file
@ -0,0 +1,165 @@
|
|||||||
|
/**********************************
|
||||||
|
* PlantUML Server Application CSS *
|
||||||
|
***********************************/
|
||||||
|
|
||||||
|
/************* variables *************/
|
||||||
|
:root {
|
||||||
|
color-scheme: light dark;
|
||||||
|
--font-color: black;
|
||||||
|
--font-color-disabled: #888;
|
||||||
|
--bg-color: white;
|
||||||
|
--border-color: #ccc;
|
||||||
|
--border-color-2: #aaa;
|
||||||
|
--footer-font-color: #666;
|
||||||
|
--footer-bg-color: #eee;
|
||||||
|
--modal-bg-color: #fefefe;
|
||||||
|
--file-drop-color: #eee;
|
||||||
|
}
|
||||||
|
[data-theme="dark"] {
|
||||||
|
--font-color: #ccc;
|
||||||
|
--font-color-disabled: #777;
|
||||||
|
--bg-color: #212121;
|
||||||
|
--border-color: #848484;
|
||||||
|
--border-color-2: #aaa;
|
||||||
|
--footer-font-color: #ccc;
|
||||||
|
--footer-bg-color: black;
|
||||||
|
--modal-bg-color: #424242;
|
||||||
|
--file-drop-color: #212121;
|
||||||
|
}
|
||||||
|
|
||||||
|
/************* default settings *************/
|
||||||
|
html, body {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
html {
|
||||||
|
font-family: arial,helvetica,sans-serif;
|
||||||
|
}
|
||||||
|
body {
|
||||||
|
background-color: var(--bg-color);
|
||||||
|
color: var(--font-color);
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
@media screen and (min-width: 900px) {
|
||||||
|
body {
|
||||||
|
height: 100vh;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
.app {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
input:not([type="image"]) {
|
||||||
|
background-color: var(--bg-color);
|
||||||
|
color: var(--font-color);
|
||||||
|
}
|
||||||
|
input[type="file"]::file-selector-button {
|
||||||
|
background-color: var(--bg-color);
|
||||||
|
color: var(--font-color);
|
||||||
|
}
|
||||||
|
select {
|
||||||
|
background-color: var(--bg-color);
|
||||||
|
color: var(--font-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
/************* ruler *************/
|
||||||
|
.hr {
|
||||||
|
padding: 1rem 0;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
.flex-columns > .hr {
|
||||||
|
padding: 0 1rem;
|
||||||
|
width: initial;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
.hr:after {
|
||||||
|
content: "";
|
||||||
|
display: block;
|
||||||
|
background-color: var(--border-color);
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
min-height: 3px;
|
||||||
|
min-width: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/************* wait cursor *************/
|
||||||
|
.wait {
|
||||||
|
cursor: wait;
|
||||||
|
}
|
||||||
|
.wait > * {
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/************* flex rows and columns *************/
|
||||||
|
.flex-columns {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
.flex-rows {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
.flex-main {
|
||||||
|
flex: 1 1 1px;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
.flex-columns > *, .flex-rows > * {
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*******************************************************************/
|
||||||
|
/************* header, main, footer *************/
|
||||||
|
.header {
|
||||||
|
margin-left: auto;
|
||||||
|
margin-right: auto;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.main {
|
||||||
|
margin: 1% 5%;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
.main > div {
|
||||||
|
margin: 0 1.75%;
|
||||||
|
}
|
||||||
|
.main > div:first-child {
|
||||||
|
margin-left: 0;
|
||||||
|
}
|
||||||
|
.main > div:last-child {
|
||||||
|
margin-right: 0;
|
||||||
|
}
|
||||||
|
@media screen and (max-width: 900px) {
|
||||||
|
.main {
|
||||||
|
display: block;
|
||||||
|
overflow: inherit;
|
||||||
|
}
|
||||||
|
.main > div {
|
||||||
|
margin: 1.75% 0;
|
||||||
|
}
|
||||||
|
.main > div:first-child {
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
.main > div:last-child {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.footer p {
|
||||||
|
background-color: var(--footer-bg-color);
|
||||||
|
color: var(--footer-font-color);
|
||||||
|
font-size: 0.7em;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0.5em;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*******************************************************************/
|
||||||
|
/************* color themes *************/
|
||||||
|
[data-theme="dark"] img:not(#diagram-png):not(.no-filter) {
|
||||||
|
filter: invert() contrast(30%);
|
||||||
|
}
|
||||||
|
[data-theme="dark"] input[type="image"] {
|
||||||
|
filter: invert() contrast(30%);
|
||||||
|
}
|
||||||
|
[data-theme="dark"] a {
|
||||||
|
color: white;
|
||||||
|
}
|
46
src/main/webapp/components/app.js
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
/*********************************
|
||||||
|
* PlantUML Server Application JS *
|
||||||
|
**********************************/
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
async function initApp() {
|
||||||
|
const view = new URL(window.location.href).searchParams.get("view")?.toLowerCase();
|
||||||
|
|
||||||
|
function initializeAppData() {
|
||||||
|
const analysedUrl = analyseUrl(window.location.href);
|
||||||
|
const code = document.editor?.getValue();
|
||||||
|
document.appData = Object.assign({}, window.opener?.document.appData);
|
||||||
|
if (Object.keys(document.appData).length === 0) {
|
||||||
|
document.appData = {
|
||||||
|
encodedDiagram: analysedUrl.encodedDiagram,
|
||||||
|
index: analysedUrl.index,
|
||||||
|
numberOfDiagramPages: (code) ? getNumberOfDiagramPagesFromCode(code) : 1,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await initEditor(view);
|
||||||
|
initializeAppData();
|
||||||
|
initTheme();
|
||||||
|
initAppCommunication();
|
||||||
|
await initPreview(view);
|
||||||
|
initModals(view);
|
||||||
|
|
||||||
|
if (document.editor) {
|
||||||
|
document.editor.focus();
|
||||||
|
if (document.appData.encodedDiagram == "SyfFKj2rKt3CoKnELR1Io4ZDoSa70000") {
|
||||||
|
// if default `Bob -> Alice : hello` example mark example code for faster editing
|
||||||
|
document.editor.setSelection({
|
||||||
|
startLineNumber: 2,
|
||||||
|
endLineNumber: 2,
|
||||||
|
startColumn: 1,
|
||||||
|
endColumn: 21,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
document.appConfig.autoRefreshState = "complete";
|
||||||
|
}
|
||||||
|
|
||||||
|
// main entry
|
||||||
|
window.onload = initApp;
|
28
src/main/webapp/components/editor/editor.css
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
/*************
|
||||||
|
* Editor CSS *
|
||||||
|
**************/
|
||||||
|
|
||||||
|
.editor {
|
||||||
|
border: 3px solid var(--border-color);
|
||||||
|
box-sizing: border-box;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
@media screen and (max-width: 900px) {
|
||||||
|
.editor {
|
||||||
|
height: 20em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.editor .monaco-editor-container {
|
||||||
|
overflow: hidden;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
#monaco-editor {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
/* Hack to display the icons and emojis in the auto completion documentation in a visible size.
|
||||||
|
* (see PlantUmlLanguageFeatures.register{Icon,Emoji}Completion) */
|
||||||
|
#monaco-editor .overlayWidgets .suggest-details p img[alt="icon"],
|
||||||
|
#monaco-editor .overlayWidgets .suggest-details p img[alt="emoji"] {
|
||||||
|
height: 1.2rem;
|
||||||
|
}
|
112
src/main/webapp/components/editor/editor.js
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
/************
|
||||||
|
* Editor JS *
|
||||||
|
*************/
|
||||||
|
|
||||||
|
const { setEditorValue, initEditor } = (function() {
|
||||||
|
function setEditorValue(
|
||||||
|
editor,
|
||||||
|
text,
|
||||||
|
{ suppressEditorChangedMessage=false, forceMoveMarkers=undefined } = {}
|
||||||
|
) {
|
||||||
|
if (suppressEditorChangedMessage && editor === document.editor) {
|
||||||
|
suppressNextMessage("editor");
|
||||||
|
}
|
||||||
|
// replace editor value but preserve undo stack
|
||||||
|
editor.executeEdits("", [{ range: editor.getModel().getFullModelRange(), text, forceMoveMarkers }]);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function initEditor(view) {
|
||||||
|
function loadMonacoCodeEditorAsync() {
|
||||||
|
return new Promise((resolve, _reject) => {
|
||||||
|
require.config({ paths: { vs: "webjars/monaco-editor/0.36.1/min/vs" } });
|
||||||
|
require(["vs/editor/editor.main"], resolve);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
function createEditorModel() {
|
||||||
|
let plantumlFeatures;
|
||||||
|
function onPlantumlEditorContentChanged(code, sender=undefined, broadcastChanges=true) {
|
||||||
|
function broadcastCodeEditorChanges() {
|
||||||
|
document.appConfig.autoRefreshState = "started";
|
||||||
|
const numberOfDiagramPages = getNumberOfDiagramPagesFromCode(code);
|
||||||
|
let index = document.appData.index;
|
||||||
|
if (index === undefined || numberOfDiagramPages === 1) {
|
||||||
|
index = undefined;
|
||||||
|
} else if (index >= numberOfDiagramPages) {
|
||||||
|
index = numberOfDiagramPages - 1;
|
||||||
|
}
|
||||||
|
makeRequest("POST", "coder", { data: code }).then((encodedDiagram) => {
|
||||||
|
sendMessage({
|
||||||
|
sender,
|
||||||
|
data: { encodedDiagram, numberOfDiagramPages, index },
|
||||||
|
synchronize: true,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
const updatePlantumlLanguageMarkers = (function() {
|
||||||
|
return function() {
|
||||||
|
const model = document.editor.getModel();
|
||||||
|
plantumlFeatures = plantumlFeatures || new PlantUmlLanguageFeatures();
|
||||||
|
plantumlFeatures.validateCode(model)
|
||||||
|
.then(markers => monaco.editor.setModelMarkers(model, "plantuml", markers));
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
if (sender && broadcastChanges) broadcastCodeEditorChanges();
|
||||||
|
updatePlantumlLanguageMarkers();
|
||||||
|
}
|
||||||
|
function getInitPlantumlCodeAndRemoveElement() {
|
||||||
|
const initCodeEl = document.getElementById("initCode");
|
||||||
|
const initCode = initCodeEl.value;
|
||||||
|
initCodeEl.remove();
|
||||||
|
return initCode;
|
||||||
|
}
|
||||||
|
// create editor model
|
||||||
|
const model = monaco.editor.createModel(
|
||||||
|
getInitPlantumlCodeAndRemoveElement(),
|
||||||
|
"apex",
|
||||||
|
monaco.Uri.parse("inmemory://plantuml")
|
||||||
|
);
|
||||||
|
// create editor model watcher
|
||||||
|
let timer = 0;
|
||||||
|
model.onDidChangeContent(() => {
|
||||||
|
clearTimeout(timer);
|
||||||
|
document.appConfig.autoRefreshState = "waiting";
|
||||||
|
timer = setTimeout(
|
||||||
|
() => onPlantumlEditorContentChanged(model.getValue(), "editor"),
|
||||||
|
document.appConfig.editorWatcherTimeout
|
||||||
|
);
|
||||||
|
});
|
||||||
|
return model;
|
||||||
|
}
|
||||||
|
function getDefaultStorageService() {
|
||||||
|
// create own storage service to expand suggestion documentation by default
|
||||||
|
return {
|
||||||
|
get() {},
|
||||||
|
getBoolean(key) { return key === "expandSuggestionDocs"; },
|
||||||
|
getNumber() { return 0; },
|
||||||
|
remove() {},
|
||||||
|
store() {},
|
||||||
|
onWillSaveState() {},
|
||||||
|
onDidChangeStorage() {},
|
||||||
|
onDidChangeValue() {},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// load monaco editor requirements
|
||||||
|
await loadMonacoCodeEditorAsync();
|
||||||
|
if (view !== "previewer") {
|
||||||
|
// create editor
|
||||||
|
const model = createEditorModel();
|
||||||
|
const storageService = getDefaultStorageService();
|
||||||
|
document.editor = monaco.editor.create(document.getElementById("monaco-editor"), {
|
||||||
|
model, ...document.appConfig.editorCreateOptions
|
||||||
|
}, { storageService });
|
||||||
|
// sometimes the monaco editor has resize problems
|
||||||
|
document.addEventListener("resize", () => document.editor.layout());
|
||||||
|
// init editor components
|
||||||
|
initEditorUrlInput();
|
||||||
|
initEditorMenu();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return { setEditorValue, initEditor };
|
||||||
|
})();
|
10
src/main/webapp/components/editor/editor.jsp
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
<div id="editor-main-container" class="editor flex-main flex-rows">
|
||||||
|
<div>
|
||||||
|
<%@ include file="/components/editor/url-input/editor-url-input.jsp" %>
|
||||||
|
</div>
|
||||||
|
<div class="flex-main monaco-editor-container">
|
||||||
|
<textarea id="initCode" name="initCode" style="display: none;"><%= net.sourceforge.plantuml.servlet.PlantUmlServlet.stringToHTMLString(decoded) %></textarea>
|
||||||
|
<div id="monaco-editor"></div>
|
||||||
|
<%@ include file="/components/editor/menu/editor-menu.jsp" %>
|
||||||
|
</div>
|
||||||
|
</div>
|
92
src/main/webapp/components/editor/menu/editor-menu.css
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
/******************
|
||||||
|
* Editor Menu CSS *
|
||||||
|
*******************/
|
||||||
|
|
||||||
|
.monaco-editor-container .editor-menu {
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
top: 0;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
.monaco-editor-container .editor-menu > div.menu-kebab {
|
||||||
|
width: 60px;
|
||||||
|
height: 60px;
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
cursor: pointer;
|
||||||
|
scale: 0.5;
|
||||||
|
}
|
||||||
|
.monaco-editor-container .editor-menu:hover > div.menu-kebab,
|
||||||
|
.monaco-editor-container .editor-menu:focus > div.menu-kebab {
|
||||||
|
outline: none;
|
||||||
|
scale: 0.65;
|
||||||
|
}
|
||||||
|
.monaco-editor-container .menu-kebab .kebab-circle {
|
||||||
|
width: 12px;
|
||||||
|
height: 12px;
|
||||||
|
margin: 3px;
|
||||||
|
background: var(--font-color);
|
||||||
|
border-radius: 50%;
|
||||||
|
display: block;
|
||||||
|
opacity: 0.8;
|
||||||
|
}
|
||||||
|
.monaco-editor-container .menu-kebab {
|
||||||
|
flex-direction: column;
|
||||||
|
position: relative;
|
||||||
|
transition: all 300ms cubic-bezier(0.175, 0.885, 0.32, 1.275);
|
||||||
|
}
|
||||||
|
.monaco-editor-container .menu-kebab .kebab-circle:nth-child(4),
|
||||||
|
.monaco-editor-container .menu-kebab .kebab-circle:nth-child(5) {
|
||||||
|
position: absolute;
|
||||||
|
opacity: 0;
|
||||||
|
top: 50%;
|
||||||
|
margin-top: -6px;
|
||||||
|
left: 50%;
|
||||||
|
}
|
||||||
|
.monaco-editor-container .menu-kebab .kebab-circle:nth-child(4) {
|
||||||
|
margin-left: -25px;
|
||||||
|
}
|
||||||
|
.monaco-editor-container .menu-kebab .kebab-circle:nth-child(5) {
|
||||||
|
margin-left: 13px;
|
||||||
|
}
|
||||||
|
.monaco-editor-container .editor-menu:hover .menu-kebab,
|
||||||
|
.monaco-editor-container .editor-menu:focus .menu-kebab {
|
||||||
|
transform: rotate(45deg);
|
||||||
|
}
|
||||||
|
.monaco-editor-container .editor-menu:hover .menu-kebab .kebab-circle,
|
||||||
|
.monaco-editor-container .editor-menu:focus .menu-kebab .kebab-circle {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.monaco-editor-container .editor-menu .menu-item {
|
||||||
|
display: none;
|
||||||
|
margin: 1rem 0;
|
||||||
|
height: 1.75rem;
|
||||||
|
opacity: 0.5;
|
||||||
|
position: relative;
|
||||||
|
-webkit-animation-name: editor-menu-animateitem;
|
||||||
|
-webkit-animation-duration: 0.4s;
|
||||||
|
animation-name: editor-menu-animateitem;
|
||||||
|
animation-duration: 0.4s;
|
||||||
|
}
|
||||||
|
@-webkit-keyframes editor-menu-animateitem {
|
||||||
|
from { top: -50%; opacity: 0; }
|
||||||
|
to { top: 0; opacity: 0.5; }
|
||||||
|
}
|
||||||
|
@keyframes editor-menu-animateitem {
|
||||||
|
from { top: -50%; opacity: 0; }
|
||||||
|
to { top: 0; opacity: 0.5; }
|
||||||
|
}
|
||||||
|
.monaco-editor-container .editor-menu .menu-item:hover {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
.monaco-editor-container .editor-menu:hover .menu-item,
|
||||||
|
.monaco-editor-container .editor-menu:focus .menu-item {
|
||||||
|
display: block;
|
||||||
|
}
|
15
src/main/webapp/components/editor/menu/editor-menu.js
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
/*****************
|
||||||
|
* Editor Menu JS *
|
||||||
|
******************/
|
||||||
|
|
||||||
|
function initEditorMenu() {
|
||||||
|
function copyCodeToClipboard() {
|
||||||
|
const range = document.editor.getModel().getFullModelRange();
|
||||||
|
document.editor.focus();
|
||||||
|
document.editor.setSelection(range);
|
||||||
|
const code = document.editor.getValue();
|
||||||
|
navigator.clipboard?.writeText(code).catch(() => {});
|
||||||
|
}
|
||||||
|
// add listener
|
||||||
|
document.getElementById("menu-item-editor-code-copy").addEventListener("click", copyCodeToClipboard);
|
||||||
|
}
|
35
src/main/webapp/components/editor/menu/editor-menu.jsp
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
<div class="editor-menu" tabindex="-1">
|
||||||
|
<div class="menu-kebab">
|
||||||
|
<div class="kebab-circle"></div>
|
||||||
|
<div class="kebab-circle"></div>
|
||||||
|
<div class="kebab-circle"></div>
|
||||||
|
<div class="kebab-circle"></div>
|
||||||
|
<div class="kebab-circle"></div>
|
||||||
|
</div>
|
||||||
|
<div class="menu-items">
|
||||||
|
<input
|
||||||
|
id="menu-item-editor-code-copy"
|
||||||
|
class="menu-item"
|
||||||
|
type="image"
|
||||||
|
alt="copy"
|
||||||
|
title="Copy code"
|
||||||
|
src="assets/actions/copy.svg"
|
||||||
|
/>
|
||||||
|
<input
|
||||||
|
class="menu-item"
|
||||||
|
type="image"
|
||||||
|
alt="import"
|
||||||
|
title="Import diagram"
|
||||||
|
src="assets/actions/upload.svg"
|
||||||
|
onclick="openModal('diagram-import')"
|
||||||
|
/>
|
||||||
|
<input
|
||||||
|
class="menu-item"
|
||||||
|
type="image"
|
||||||
|
alt="export"
|
||||||
|
title="Export diagram"
|
||||||
|
src="assets/actions/download.svg"
|
||||||
|
onclick="openModal('diagram-export')"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
@ -0,0 +1,29 @@
|
|||||||
|
/***********************
|
||||||
|
* Editor URL Input CSS *
|
||||||
|
************************/
|
||||||
|
|
||||||
|
.editor .btn-input {
|
||||||
|
align-items: center;
|
||||||
|
border-bottom: 3px solid var(--border-color);
|
||||||
|
box-sizing: border-box;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
.editor .btn-input input[type=text] {
|
||||||
|
border: 0;
|
||||||
|
flex: 1 1 1px;
|
||||||
|
font-family: monospace;
|
||||||
|
font-size: medium;
|
||||||
|
padding: 0.2em;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
.editor .btn-input input[type=text]:focus {
|
||||||
|
border: 0;
|
||||||
|
box-shadow: none;
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
.editor .btn-input input[type="image"] {
|
||||||
|
height: 1rem;
|
||||||
|
margin-left: 0.7em;
|
||||||
|
padding: 0 0.3em;
|
||||||
|
}
|
@ -0,0 +1,53 @@
|
|||||||
|
/**********************
|
||||||
|
* Editor URL Input JS *
|
||||||
|
***********************/
|
||||||
|
|
||||||
|
const { setUrlValue, initEditorUrlInput } = (function() {
|
||||||
|
function setUrlValue(
|
||||||
|
url=undefined,
|
||||||
|
{ encodedDiagram=undefined, index=undefined } = {},
|
||||||
|
{ suppressEditorChangedMessage=false } = {}
|
||||||
|
) {
|
||||||
|
if (!url && !encodedDiagram) return;
|
||||||
|
if (suppressEditorChangedMessage) {
|
||||||
|
suppressNextMessage("url");
|
||||||
|
}
|
||||||
|
document.getElementById("url").value = url ? url : resolvePath(buildUrl("png", encodedDiagram, index));
|
||||||
|
}
|
||||||
|
|
||||||
|
function initEditorUrlInput() {
|
||||||
|
const input = document.getElementById("url");
|
||||||
|
|
||||||
|
function copyUrlToClipboard() {
|
||||||
|
input.focus();
|
||||||
|
input.select();
|
||||||
|
navigator.clipboard?.writeText(input.value).catch(() => {});
|
||||||
|
}
|
||||||
|
async function onInputChanged(event) {
|
||||||
|
document.appConfig.autoRefreshState = "started";
|
||||||
|
event.target.title = event.target.value;
|
||||||
|
const analysedUrl = analyseUrl(event.target.value);
|
||||||
|
// decode diagram (server request)
|
||||||
|
const code = await makeRequest("GET", "coder/" + analysedUrl.encodedDiagram);
|
||||||
|
// change editor content without sending the editor change message
|
||||||
|
setEditorValue(document.editor, code, { suppressEditorChangedMessage: true });
|
||||||
|
sendMessage({
|
||||||
|
sender: "url",
|
||||||
|
data: {
|
||||||
|
encodedDiagram: analysedUrl.encodedDiagram,
|
||||||
|
index: analysedUrl.index,
|
||||||
|
},
|
||||||
|
synchronize: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// resolve relative path inside url input once
|
||||||
|
setUrlValue(resolvePath(input.value));
|
||||||
|
// update editor and everything else if the URL input is changed
|
||||||
|
input.addEventListener("change", onInputChanged);
|
||||||
|
// add listener
|
||||||
|
document.getElementById("url-copy-btn").addEventListener("click", copyUrlToClipboard);
|
||||||
|
}
|
||||||
|
|
||||||
|
return { setUrlValue, initEditorUrlInput };
|
||||||
|
})();
|
@ -0,0 +1,4 @@
|
|||||||
|
<div class="btn-input">
|
||||||
|
<input id="url" type="text" name="url" value="png/<%= diagramUrl %>" />
|
||||||
|
<input id="url-copy-btn" type="image" alt="copy" src="assets/actions/copy.svg" tabindex="-1" />
|
||||||
|
</div>
|
1
src/main/webapp/components/footer/footer.jsp
Normal file
@ -0,0 +1 @@
|
|||||||
|
<p><%= net.sourceforge.plantuml.version.Version.fullDescription() %></p>
|
17
src/main/webapp/components/header/github-ribbon.jsp
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
<div>
|
||||||
|
<img
|
||||||
|
style="display: inline; position: absolute; top: 0; right: 0; border: 0; max-width: 25%;"
|
||||||
|
class="no-filter"
|
||||||
|
src="assets/github-fork-me.svg"
|
||||||
|
alt="Fork me on GitHub"
|
||||||
|
usemap="#github-banner"
|
||||||
|
/>
|
||||||
|
<map id="github-banner" name="github-banner" style="cursor: pointer;">
|
||||||
|
<area
|
||||||
|
shape="poly"
|
||||||
|
coords="10,0 50,0 149,100 149,140"
|
||||||
|
href="https://github.com/plantuml/plantuml-server"
|
||||||
|
alt="Fork me on GitHub"
|
||||||
|
/>
|
||||||
|
</map>
|
||||||
|
</div>
|
8
src/main/webapp/components/header/header.jsp
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<h1>PlantUML Server</h1>
|
||||||
|
<% if (showSocialButtons) { %>
|
||||||
|
<%@ include file="/components/header/social-buttons.jsp" %>
|
||||||
|
<% } %>
|
||||||
|
<% if (showGithubRibbon) { %>
|
||||||
|
<%@ include file="/components/header/github-ribbon.jsp" %>
|
||||||
|
<% } %>
|
||||||
|
<p>Create your <a href="https://plantuml.com">PlantUML</a> diagrams directly in your browser!</p>
|
1
src/main/webapp/components/header/social-buttons.jsp
Normal file
@ -0,0 +1 @@
|
|||||||
|
<!-- Insert here the html code of your social buttons -->
|
@ -0,0 +1,7 @@
|
|||||||
|
/*********************
|
||||||
|
* Diagram Export CSS *
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
#diagram-export.modal .label-input-pair label {
|
||||||
|
min-width: 8rem;
|
||||||
|
}
|
@ -0,0 +1,97 @@
|
|||||||
|
/********************
|
||||||
|
* Diagram Export JS *
|
||||||
|
*********************/
|
||||||
|
|
||||||
|
function initDiagramExport() {
|
||||||
|
const filenameInput = document.getElementById("download-name");
|
||||||
|
const fileTypeSelect = document.getElementById("download-type");
|
||||||
|
|
||||||
|
function openDiagramExportDialog() {
|
||||||
|
setVisibility(document.getElementById("diagram-export"), true, true);
|
||||||
|
const code = document.editor.getValue();
|
||||||
|
const name = Array.from(
|
||||||
|
code.matchAll(/^\s*@start[a-zA-Z]*\s+([a-zA-Z-_äöüÄÖÜß ]+)\s*$/gm),
|
||||||
|
m => m[1]
|
||||||
|
)[0] || "diagram";
|
||||||
|
filenameInput.value = name + ".puml";
|
||||||
|
fileTypeSelect.value = "code";
|
||||||
|
filenameInput.focus();
|
||||||
|
}
|
||||||
|
function splitFilename(filename) {
|
||||||
|
const idx = filename.lastIndexOf(".");
|
||||||
|
if (idx < 1) {
|
||||||
|
return { name: filename, ext: null };
|
||||||
|
}
|
||||||
|
if (idx === filename.length - 1) {
|
||||||
|
return { name: filename.slice(0, -1), ext: null };
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
name: filename.substring(0, idx),
|
||||||
|
ext: filename.substring(idx + 1),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
function getExtensionByType(type) {
|
||||||
|
switch (type) {
|
||||||
|
case "epstext": return "eps";
|
||||||
|
case "code": return "puml";
|
||||||
|
default: return type;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function getTypeByExtension(ext) {
|
||||||
|
if (!ext) return ext;
|
||||||
|
ext = ext.toLowerCase();
|
||||||
|
switch (ext) {
|
||||||
|
case "puml":
|
||||||
|
case "plantuml":
|
||||||
|
case "code":
|
||||||
|
return "code";
|
||||||
|
case "ascii": return "txt"
|
||||||
|
default: return ext;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function onTypeChanged(event) {
|
||||||
|
const type = event.target.value;
|
||||||
|
const ext = getExtensionByType(type);
|
||||||
|
const { name } = splitFilename(filenameInput.value);
|
||||||
|
filenameInput.value = name + "." + ext;
|
||||||
|
}
|
||||||
|
function onFilenameChanged(event) {
|
||||||
|
const { ext } = splitFilename(event.target.value);
|
||||||
|
const type = getTypeByExtension(ext);
|
||||||
|
if (!type) return;
|
||||||
|
fileTypeSelect.value = type;
|
||||||
|
}
|
||||||
|
function downloadFile() {
|
||||||
|
const filename = filenameInput.value;
|
||||||
|
const type = fileTypeSelect.value;
|
||||||
|
const link = document.createElement("a");
|
||||||
|
link.download = filename;
|
||||||
|
if (type === "code") {
|
||||||
|
const code = document.editor.getValue();
|
||||||
|
link.href = "data:," + encodeURIComponent(code);
|
||||||
|
} else {
|
||||||
|
if (document.appData.index !== undefined) {
|
||||||
|
link.href = type + "/" + document.appData.index + "/" + document.appData.encodedDiagram;
|
||||||
|
} else {
|
||||||
|
link.href = type + "/" + document.appData.encodedDiagram;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
link.click();
|
||||||
|
}
|
||||||
|
|
||||||
|
// register modal
|
||||||
|
registerModalListener("diagram-export", openDiagramExportDialog);
|
||||||
|
// add listener
|
||||||
|
filenameInput.addEventListener("change", onFilenameChanged);
|
||||||
|
fileTypeSelect.addEventListener("change", onTypeChanged);
|
||||||
|
document.getElementById("diagram-export-ok-btn").addEventListener("click", downloadFile);
|
||||||
|
// add Ctrl+S or Meta+S (Mac) key shortcut to open export dialog
|
||||||
|
window.addEventListener("keydown", event => {
|
||||||
|
if (event.key === "s" && (isMac ? event.metaKey : event.ctrlKey)) {
|
||||||
|
event.preventDefault();
|
||||||
|
if (!isModalOpen("diagram-export")) {
|
||||||
|
openDiagramExportDialog();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, false);
|
||||||
|
}
|
@ -0,0 +1,32 @@
|
|||||||
|
<div id="diagram-export" class="modal" style="display: none;" tabindex="-1">
|
||||||
|
<div class="modal-content flex-rows">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h2>Export Diagram</h2>
|
||||||
|
<div class="hr"></div>
|
||||||
|
</div>
|
||||||
|
<div class="modal-main flex-main">
|
||||||
|
<div class="label-input-pair flex-columns">
|
||||||
|
<label for="download-name">Diagram name:</label>
|
||||||
|
<input class="flex-main" id="download-name" value="diagram.puml" />
|
||||||
|
</div>
|
||||||
|
<div class="label-input-pair flex-columns">
|
||||||
|
<label for="download-type">Diagram type:</label>
|
||||||
|
<select class="flex-main" id="download-type" name="download-type">
|
||||||
|
<option value="txt">ASCII Art</option>
|
||||||
|
<option value="base64">Base64</option>
|
||||||
|
<option value="eps">EPS</option>
|
||||||
|
<option value="epstext">EPS Text</option>
|
||||||
|
<option value="map">MAP</option>
|
||||||
|
<option value="pdf">PDF</option>
|
||||||
|
<option value="code" selected>PlantUML source code</option>
|
||||||
|
<option value="png">PNG</option>
|
||||||
|
<option value="svg">SVG</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<input id="diagram-export-ok-btn" class="ok" type="button" value="Export" />
|
||||||
|
<input class="cancel" type="button" value="Cancel" onclick="closeModal('diagram-export')" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
30
src/main/webapp/components/modals/diagram-import/diagram-import.css
vendored
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
/*********************
|
||||||
|
* Diagram Import CSS *
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
#diagram-import p.error-message {
|
||||||
|
color: darkred;
|
||||||
|
padding-left: 1rem;
|
||||||
|
padding-right: 1rem;
|
||||||
|
}
|
||||||
|
#diagram-import input[type="file"] {
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
border: 0.2rem dashed var(--border-color);
|
||||||
|
border-radius: 0.4rem;
|
||||||
|
box-sizing: border-box;
|
||||||
|
padding: 5rem 2rem;
|
||||||
|
}
|
||||||
|
#diagram-import input[type="file"],
|
||||||
|
#diagram-import input[type="file"]::file-selector-button {
|
||||||
|
background-color: var(--modal-bg-color);
|
||||||
|
}
|
||||||
|
#diagram-import input[type="file"]:hover,
|
||||||
|
#diagram-import input[type="file"].drop-able {
|
||||||
|
border-color: var(--border-color-2);
|
||||||
|
background-color: var(--file-drop-color);
|
||||||
|
}
|
||||||
|
#diagram-import input[type="file"]:hover::file-selector-button,
|
||||||
|
#diagram-import input[type="file"].drop-able::file-selector-button {
|
||||||
|
background-color: var(--file-drop-color);
|
||||||
|
}
|
@ -0,0 +1,152 @@
|
|||||||
|
/********************
|
||||||
|
* Diagram Import JS *
|
||||||
|
*********************/
|
||||||
|
|
||||||
|
function initDiagramImport() {
|
||||||
|
const dialogElement = document.getElementById("diagram-import");
|
||||||
|
const fileInput = document.getElementById("diagram-import-input");
|
||||||
|
const okButton = document.getElementById("diagram-import-ok-btn");
|
||||||
|
const errorMessageElement = document.getElementById("diagram-import-error-message");
|
||||||
|
|
||||||
|
function openDialog(isOpenManually = true) {
|
||||||
|
setVisibility(dialogElement, true, true);
|
||||||
|
dialogElement.dataset.isOpenManually = isOpenManually.toString();
|
||||||
|
// reset or clear file input
|
||||||
|
fileInput.value = "";
|
||||||
|
onFileInputChange(fileInput);
|
||||||
|
}
|
||||||
|
function closeDialog() {
|
||||||
|
fileInput.value = ""; // reset or clear
|
||||||
|
onFileInputChange(fileInput);
|
||||||
|
dialogElement.removeAttribute("data-is-open-manually");
|
||||||
|
setVisibility(dialogElement, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
function onFileInputChange(fileInput) {
|
||||||
|
errorMessageElement.innerText = "";
|
||||||
|
okButton.disabled = fileInput.files?.length < 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
function checkFileLocally(file) {
|
||||||
|
function getImageFileType({name, type}) {
|
||||||
|
const supported = ["png", "svg"];
|
||||||
|
// get type by mime type
|
||||||
|
let fileType = supported.filter(t => type.toLowerCase().indexOf(t) !== -1)[0];
|
||||||
|
if (fileType) return fileType;
|
||||||
|
// fallback: get type by filename extension
|
||||||
|
if (name.indexOf(".") === -1) return undefined;
|
||||||
|
const ext = name.substring(name.lastIndexOf(".")+1).toLowerCase();
|
||||||
|
return supported.filter(t => ext === t)[0];
|
||||||
|
}
|
||||||
|
function isDiagramCode({name, type}) {
|
||||||
|
// get type by mime type
|
||||||
|
let supported = ["plain", "text", "plantuml", "puml"];
|
||||||
|
if (supported.filter(t => type.toLowerCase().indexOf(t) !== -1).length > 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// fallback: get type by filename extension
|
||||||
|
if (name.indexOf(".") === -1) return false;
|
||||||
|
const ext = name.substring(name.lastIndexOf('.')+1).toLowerCase();
|
||||||
|
supported = ["txt", "puml", "plantuml"];
|
||||||
|
return supported.filter(t => ext === t).length > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const type = getImageFileType(file);
|
||||||
|
const isCode = type === undefined ? isDiagramCode(file) : false;
|
||||||
|
if (!type && !isCode) {
|
||||||
|
errorMessageElement.innerText = "File not supported. " +
|
||||||
|
"Only PNG and SVG diagram images as well as PlantUML code text files are supported."
|
||||||
|
}
|
||||||
|
return { type, isDiagramCode: isCode, valid: type || isCode };
|
||||||
|
}
|
||||||
|
|
||||||
|
function importDiagram(file, fileCheck) {
|
||||||
|
function loadDiagram(code) {
|
||||||
|
setEditorValue(document.editor, code);
|
||||||
|
}
|
||||||
|
function requestMetadata(file) {
|
||||||
|
const fd = new FormData();
|
||||||
|
fd.append("diagram", file, file.name);
|
||||||
|
return makeRequest("POST", "metadata", {
|
||||||
|
data: fd,
|
||||||
|
responseType: "json",
|
||||||
|
headers: { "Accept": "application/json" },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
dialogElement.classList.add("wait");
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
if (fileCheck.type) {
|
||||||
|
// upload diagram image, get meta data from server and load diagram from result
|
||||||
|
requestMetadata(file).then(
|
||||||
|
metadata => { loadDiagram(metadata.decoded); resolve(); },
|
||||||
|
({ response }) => { errorMessageElement.innerText = response.message || response; reject(); }
|
||||||
|
);
|
||||||
|
} else if (fileCheck.isDiagramCode) {
|
||||||
|
// read code (text) file
|
||||||
|
const reader = new FileReader();
|
||||||
|
reader.onload = event => loadDiagram(event.target.result);
|
||||||
|
reader.readAsText(file);
|
||||||
|
resolve();
|
||||||
|
} else {
|
||||||
|
// this error should already be handled.
|
||||||
|
errorMessageElement.innerText = "File not supported. " +
|
||||||
|
"Only PNG and SVG diagram images as well as PlantUML code text files are supported.";
|
||||||
|
reject();
|
||||||
|
}
|
||||||
|
}).then(() => closeDialog(), () => {}).finally(() => dialogElement.classList.remove("wait"));
|
||||||
|
}
|
||||||
|
|
||||||
|
function onGlobalDragEnter(event) {
|
||||||
|
event.stopPropagation();
|
||||||
|
event.preventDefault();
|
||||||
|
if (!isVisible(dialogElement)) {
|
||||||
|
openDialog(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function onFileInputDragOver(event) {
|
||||||
|
event.stopPropagation();
|
||||||
|
event.preventDefault();
|
||||||
|
if (event.dataTransfer !== null) {
|
||||||
|
event.dataTransfer.dropEffect = "copy";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function onFileInputDrop(event) {
|
||||||
|
function stop() {
|
||||||
|
event.stopPropagation();
|
||||||
|
event.preventDefault();
|
||||||
|
}
|
||||||
|
const files = event.dataTransfer.files || event.target.files;
|
||||||
|
if (!files || files.length < 1) {
|
||||||
|
return stop();
|
||||||
|
}
|
||||||
|
const file = files[0];
|
||||||
|
const fileCheck = checkFileLocally(file);
|
||||||
|
if (!fileCheck.valid) {
|
||||||
|
return stop();
|
||||||
|
}
|
||||||
|
if (dialogElement.dataset.isOpenManually === "true") {
|
||||||
|
return; // let file input handle this event => no `stop()`!
|
||||||
|
}
|
||||||
|
// drop and go - close modal without additional ok button click
|
||||||
|
stop();
|
||||||
|
importDiagram(file, fileCheck);
|
||||||
|
}
|
||||||
|
|
||||||
|
// global drag&drop events
|
||||||
|
window.addEventListener("dragenter", onGlobalDragEnter, false);
|
||||||
|
// diagram import dialog drag&drop events
|
||||||
|
fileInput.addEventListener("dragenter", event => event.target.classList.add("drop-able"), false);
|
||||||
|
fileInput.addEventListener("dragover", onFileInputDragOver, false);
|
||||||
|
fileInput.addEventListener("dragexit", event => event.target.classList.remove("drop-able"), false);
|
||||||
|
fileInput.addEventListener("drop", onFileInputDrop, false);
|
||||||
|
fileInput.addEventListener("change", event => onFileInputChange(event.target));
|
||||||
|
// ok button
|
||||||
|
okButton.addEventListener("click", () => {
|
||||||
|
const file = fileInput.files[0]; // should be always a valid file
|
||||||
|
importDiagram(file, checkFileLocally(file)); // otherwise button should be disabled
|
||||||
|
});
|
||||||
|
// register model listeners
|
||||||
|
registerModalListener("diagram-import", openDialog, closeDialog);
|
||||||
|
}
|