Compare commits
121 Commits
v1.2021.14
...
master
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 | ||
|
dd028e9579 | ||
|
94678b720e | ||
|
b5c21c76b6 | ||
|
ca3e9312b3 | ||
|
ba6af87b2d | ||
|
249163e149 | ||
|
0330b7c4a2 | ||
|
cebca916fe | ||
|
d5ef062af4 | ||
|
74f35846a7 | ||
|
e83dfa2b3a | ||
|
8c45a7b106 | ||
|
f14337933d | ||
|
c94711c2d5 | ||
|
b995dcdb61 | ||
|
494dfba063 | ||
|
c8954cbe4a | ||
|
5e0ccaf328 | ||
|
86bb70d079 | ||
|
da290a15fe | ||
|
12224aa16e | ||
|
c5f088e50a | ||
|
54016d325d | ||
|
7b0022de44 | ||
|
32e05b62bd | ||
|
e5cb82ef2c | ||
|
7c578c482f | ||
|
422ebe1792 | ||
|
67fbe35fc3 | ||
|
807ca66fe1 |
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
|
5
.github/FUNDING.yml
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
# These are supported funding model platforms
|
||||
|
||||
github: plantuml
|
||||
patreon: plantuml
|
||||
liberapay: plantuml
|
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.
|
30
.github/workflows/main.yml
vendored
@ -9,11 +9,11 @@ jobs:
|
||||
build-jdk11:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- uses: actions/setup-java@v2
|
||||
- uses: actions/setup-java@v3
|
||||
with:
|
||||
distribution: "zulu"
|
||||
java-version: 11
|
||||
@ -22,7 +22,7 @@ jobs:
|
||||
|
||||
- name: get tag name
|
||||
id: version
|
||||
run: echo ::set-output name=VERSION::${GITHUB_REF#refs/*/}
|
||||
run: echo "VERSION=${GITHUB_REF#refs/*/}" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: build with maven
|
||||
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
|
||||
|
||||
- name: temporarily save generated war files
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: war-jre11
|
||||
path: target/plantuml*-${{ steps.version.outputs.VERSION }}.war
|
||||
@ -45,11 +45,11 @@ jobs:
|
||||
build-jdk8:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- uses: actions/setup-java@v2
|
||||
- uses: actions/setup-java@v3
|
||||
with:
|
||||
distribution: "zulu"
|
||||
java-version: 8
|
||||
@ -58,7 +58,7 @@ jobs:
|
||||
|
||||
- name: get tag name
|
||||
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)
|
||||
run: rm -rf src/test
|
||||
@ -76,7 +76,7 @@ jobs:
|
||||
run: cp target/plantuml.war target/plantuml-jre8-jsp-${{ steps.version.outputs.VERSION }}.war
|
||||
|
||||
- name: temporarily save generated war files
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: war-jre8
|
||||
path: target/plantuml*-${{ steps.version.outputs.VERSION }}.war
|
||||
@ -88,13 +88,13 @@ jobs:
|
||||
- build-jdk8
|
||||
steps:
|
||||
- name: retrieve generated war files (jre8)
|
||||
uses: actions/download-artifact@v2
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: war-jre8
|
||||
path: artifacts
|
||||
|
||||
- name: retrieve generated war files (jre11)
|
||||
uses: actions/download-artifact@v2
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: war-jre11
|
||||
path: artifacts
|
||||
@ -116,7 +116,7 @@ jobs:
|
||||
needs:
|
||||
- publish-releases
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
@ -165,7 +165,7 @@ jobs:
|
||||
with:
|
||||
context: .
|
||||
file: ./Dockerfile.tomcat
|
||||
platforms: linux/amd64
|
||||
platforms: linux/amd64, linux/arm64
|
||||
push: true
|
||||
tags: ${{ steps.docker_meta_tomcat.outputs.tags }}
|
||||
labels: ${{ steps.docker_meta_tomcat.outputs.labels }}
|
||||
@ -176,7 +176,7 @@ jobs:
|
||||
with:
|
||||
context: .
|
||||
file: ./Dockerfile.jetty
|
||||
platforms: linux/amd64
|
||||
platforms: linux/amd64, linux/arm64
|
||||
push: true
|
||||
tags: ${{ steps.docker_meta_jetty.outputs.tags }}
|
||||
labels: ${{ steps.docker_meta_jetty.outputs.labels }}
|
||||
@ -186,11 +186,11 @@ jobs:
|
||||
needs:
|
||||
- publish-releases
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- uses: actions/setup-java@v2
|
||||
- uses: actions/setup-java@v3
|
||||
with:
|
||||
distribution: "zulu"
|
||||
java-version: 11
|
||||
|
52
.github/workflows/tests.yml
vendored
@ -8,11 +8,11 @@ jobs:
|
||||
test-java-8-war-generation:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- uses: actions/setup-java@v2
|
||||
- uses: actions/setup-java@v3
|
||||
with:
|
||||
distribution: "zulu"
|
||||
java-version: 8
|
||||
@ -29,7 +29,7 @@ jobs:
|
||||
run: mvn --batch-mode -f pom.jdk8.xml -D java.net.useSystemProxies=true clean package
|
||||
|
||||
- name: temporarily save generated files
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: war-jre8
|
||||
path: target/plantuml.war
|
||||
@ -42,17 +42,17 @@ jobs:
|
||||
matrix:
|
||||
java-version: [ 11, 17 ]
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: retrieve generated files (jre8)
|
||||
uses: actions/download-artifact@v2
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: war-jre8
|
||||
path: artifacts
|
||||
|
||||
- uses: actions/setup-java@v2
|
||||
- uses: actions/setup-java@v3
|
||||
with:
|
||||
distribution: "zulu"
|
||||
java-version: ${{ matrix.java-version }}
|
||||
@ -69,7 +69,7 @@ jobs:
|
||||
run: sleep 5s
|
||||
|
||||
- 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:
|
||||
runs-on: ubuntu-latest
|
||||
@ -77,11 +77,11 @@ jobs:
|
||||
matrix:
|
||||
java-version: [ 11, 17 ]
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- uses: actions/setup-java@v2
|
||||
- uses: actions/setup-java@v3
|
||||
with:
|
||||
distribution: "zulu"
|
||||
java-version: ${{ matrix.java-version }}
|
||||
@ -93,7 +93,7 @@ jobs:
|
||||
|
||||
- name: Lifecycle - Step 2/8 - mvn validate
|
||||
run: mvn --batch-mode validate
|
||||
|
||||
|
||||
- name: Lifecycle - Step 3/8 - mvn compile
|
||||
run: mvn --batch-mode compile
|
||||
|
||||
@ -111,7 +111,7 @@ jobs:
|
||||
|
||||
- name: Lifecycle - Step 8/8 - mvn site
|
||||
run: mvn --batch-mode site
|
||||
|
||||
|
||||
test-embedded:
|
||||
runs-on: ubuntu-latest
|
||||
needs: test-mvn-livecycle
|
||||
@ -119,11 +119,11 @@ jobs:
|
||||
matrix:
|
||||
java-version: [ 11, 17 ]
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- uses: actions/setup-java@v2
|
||||
- uses: actions/setup-java@v3
|
||||
with:
|
||||
distribution: "zulu"
|
||||
java-version: ${{ matrix.java-version }}
|
||||
@ -131,7 +131,7 @@ jobs:
|
||||
cache: "maven"
|
||||
|
||||
- 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:
|
||||
runs-on: ubuntu-latest
|
||||
@ -140,11 +140,11 @@ jobs:
|
||||
matrix:
|
||||
java-version: [ 11, 17 ]
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- uses: actions/setup-java@v2
|
||||
- uses: actions/setup-java@v3
|
||||
with:
|
||||
distribution: "zulu"
|
||||
java-version: ${{ matrix.java-version }}
|
||||
@ -161,7 +161,7 @@ jobs:
|
||||
run: sleep 20s
|
||||
|
||||
- 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:
|
||||
runs-on: ubuntu-latest
|
||||
@ -170,11 +170,11 @@ jobs:
|
||||
matrix:
|
||||
java-version: [ 11, 17 ]
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- uses: actions/setup-java@v2
|
||||
- uses: actions/setup-java@v3
|
||||
with:
|
||||
distribution: "zulu"
|
||||
java-version: ${{ matrix.java-version }}
|
||||
@ -191,7 +191,7 @@ jobs:
|
||||
run: sleep 5s
|
||||
|
||||
- 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:
|
||||
runs-on: ubuntu-latest
|
||||
@ -200,11 +200,11 @@ jobs:
|
||||
matrix:
|
||||
java-version: [ 11, 17 ]
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- uses: actions/setup-java@v2
|
||||
- uses: actions/setup-java@v3
|
||||
with:
|
||||
distribution: "zulu"
|
||||
java-version: ${{ matrix.java-version }}
|
||||
@ -217,7 +217,7 @@ jobs:
|
||||
- name: Build the jetty docker stack
|
||||
run: |
|
||||
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
|
||||
run: docker ps
|
||||
@ -232,11 +232,11 @@ jobs:
|
||||
matrix:
|
||||
java-version: [ 11, 17 ]
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- uses: actions/setup-java@v2
|
||||
- uses: actions/setup-java@v3
|
||||
with:
|
||||
distribution: "zulu"
|
||||
java-version: ${{ matrix.java-version }}
|
||||
@ -249,7 +249,7 @@ jobs:
|
||||
- name: Build the tomcat docker stack
|
||||
run: |
|
||||
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
|
||||
run: docker ps
|
||||
|
8
.gitignore
vendored
@ -1,5 +1,13 @@
|
||||
# Eclipse Ignores
|
||||
target
|
||||
.settings
|
||||
.classpath
|
||||
.project
|
||||
.checkstyle
|
||||
|
||||
# IntelliJ ignores
|
||||
.idea/
|
||||
out/
|
||||
*.iml
|
||||
*.ipr
|
||||
*.iws
|
18
.vscode/settings.json
vendored
@ -2,21 +2,29 @@
|
||||
"java.configuration.updateBuildConfiguration": "automatic",
|
||||
"cSpell.words": [
|
||||
"Arnaud",
|
||||
"buildx",
|
||||
"ditaa",
|
||||
"endditaa",
|
||||
"enduml",
|
||||
"epstext",
|
||||
"etag",
|
||||
"ghaction",
|
||||
"inmemory",
|
||||
"Lalloni",
|
||||
"monaco",
|
||||
"plantuml",
|
||||
"puml",
|
||||
"Roques",
|
||||
"servlet",
|
||||
"servlets",
|
||||
"startditaa",
|
||||
"startuml",
|
||||
"utxt",
|
||||
"ghaction",
|
||||
"buildx"
|
||||
"undock",
|
||||
"utxt"
|
||||
],
|
||||
"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/
|
||||
|
||||
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
|
||||
# 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
|
||||
|
||||
USER root
|
||||
|
||||
RUN apt-get update && \
|
||||
apt-get install -y --no-install-recommends \
|
||||
curl \
|
||||
fonts-noto-cjk \
|
||||
graphviz \
|
||||
libgd3 \
|
||||
&& \
|
||||
rm -rf /var/lib/apt/lists/* && \
|
||||
/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
|
||||
|
||||
USER jetty
|
||||
|
||||
ENV BASE_URL=ROOT \
|
||||
WEBAPP_PATH=$JETTY_BASE/webapps
|
||||
ENV WEBAPP_PATH=$JETTY_BASE/webapps
|
||||
RUN rm -rf $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"]
|
||||
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/
|
||||
|
||||
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 && \
|
||||
apt-get install -y --no-install-recommends \
|
||||
curl \
|
||||
fonts-noto-cjk \
|
||||
graphviz \
|
||||
libgd3 \
|
||||
&& \
|
||||
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
|
||||
|
||||
ENV BASE_URL=ROOT \
|
||||
WEBAPP_PATH=$CATALINA_HOME/webapps
|
||||
ENV WEBAPP_PATH=$CATALINA_HOME/webapps
|
||||
RUN rm -rf $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"]
|
||||
CMD ["catalina.sh", "run"]
|
||||
|
60
README.md
@ -4,14 +4,33 @@
|
||||
[![latest tag](https://img.shields.io/github/v/tag/plantuml/plantuml-server)](https://github.com/plantuml/plantuml-server/tags)
|
||||
![workflow status (Main)](https://github.com/plantuml/plantuml-server/actions/workflows/main.yml/badge.svg)
|
||||
![workflow status (Tests)](https://github.com/plantuml/plantuml-server/actions/workflows/tests.yml/badge.svg)
|
||||
![workflow status (Pages)](https://github.com/plantuml/plantuml-server/actions/workflows/pages.yml/badge.svg)
|
||||
|
||||
[![online](https://img.shields.io/endpoint?url=https://www.plantuml.com/plantuml/badge)](https://www.plantuml.com/plantuml)
|
||||
[![rate](https://img.shields.io/endpoint?url=https://www.plantuml.com/plantuml/rate)](https://www.plantuml.com/plantuml)
|
||||
[![peak](https://img.shields.io/endpoint?url=https://www.plantuml.com/plantuml/rate?peak)](https://www.plantuml.com/plantuml)
|
||||
|
||||
[![GitHub Sponsors](https://img.shields.io/github/sponsors/plantuml?logo=github)](https://github.com/sponsors/plantuml/)
|
||||
[![docker pulls](https://img.shields.io/docker/pulls/plantuml/plantuml-server.svg?color=blue)](https://hub.docker.com/r/plantuml/plantuml-server)
|
||||
![Docker Image Size (Jetty)](https://img.shields.io/docker/image-size/plantuml/plantuml-server/jetty?label=jetty%20image%20size)
|
||||
![Docker Image Size (Tomcat)](https://img.shields.io/docker/image-size/plantuml/plantuml-server/tomcat?label=tomcat%20image%20size)
|
||||
|
||||
PlantUML Server is a web application to generate UML diagrams on-the-fly.
|
||||
|
||||
![PlantUML Server](https://raw.githubusercontent.com/plantuml/plantuml-server/master/screenshots/screenshot.png)
|
||||
> [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/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.
|
||||
|
||||
@ -21,6 +40,11 @@ To know more about PlantUML, please visit https://plantuml.com.
|
||||
- jre/jdk 11 or above
|
||||
- apache maven 3.0.2 or above
|
||||
|
||||
## Recommendations
|
||||
|
||||
- Jetty 11 or above
|
||||
- Tomcat 10 or above
|
||||
|
||||
|
||||
## How to run the server
|
||||
|
||||
@ -102,6 +126,22 @@ You can set all the following variables:
|
||||
* `BASE_URL`
|
||||
* PlantUML Base URL path
|
||||
* 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`
|
||||
* Limits image width and height
|
||||
* Default value: `4096`
|
||||
@ -111,17 +151,15 @@ You can set all the following variables:
|
||||
* `HTTP_AUTHORIZATION`
|
||||
* when calling the `proxy` endpoint, the value of `HTTP_AUTHORIZATION` will be used to set the HTTP Authorization header
|
||||
* Default value: `null`
|
||||
* `ALLOW_PLANTUML_INCLUDE`
|
||||
* Enables `!include` processing which can read files from the server into diagrams. Files are read relative to the current working directory.
|
||||
* Default value: `false`
|
||||
* `HTTP_PROXY_READ_TIMEOUT`
|
||||
* when calling the `proxy` endpoint, the value of `HTTP_PROXY_READ_TIMEOUT` will be the connection read timeout in milliseconds
|
||||
* Default value: `10000` (10 seconds)
|
||||
|
||||
|
||||
## Alternate: How to build your docker image
|
||||
|
||||
This method uses maven to run the application. That requires internet connectivity.
|
||||
So, you can use following command to create a self-contained docker image that will "just-work".
|
||||
|
||||
*Note: Generate the WAR (instructions further below) prior to running "docker build"*
|
||||
So, you can use following command to create a self-contained docker image that will "just work".
|
||||
|
||||
```sh
|
||||
docker image build -f Dockerfile.jetty -t plantuml-server:local .
|
||||
@ -150,3 +188,9 @@ If you want to generate the war with java 8 as target just remove the src/test d
|
||||
rm -rf src/test
|
||||
mvn package -f pom.jdk8.xml [-Dapache-jsp.scope=compile]
|
||||
```
|
||||
|
||||
## Use with reverse-proxy
|
||||
|
||||
It is possible to use PlantUML with a reverse proxy.
|
||||
|
||||
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>
|
12
SECURITY.md
Normal file
@ -0,0 +1,12 @@
|
||||
# Security Policy
|
||||
|
||||
|
||||
|
||||
## Reporting a Vulnerability
|
||||
|
||||
If you find any security concern, please send a mail to plantuml@gmail.com
|
||||
with title **Security concern**.
|
||||
|
||||
We will then study the concern and will answer back by email.
|
||||
|
||||
Thanks!
|
@ -1,11 +1,9 @@
|
||||
version: '3.3'
|
||||
|
||||
services:
|
||||
plantuml-server:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile.jetty
|
||||
image: plantuml/plantuml-server:jetty-local
|
||||
image: plantuml/plantuml-server:jetty
|
||||
container_name: plantuml-server
|
||||
ports:
|
||||
- 8080:8080
|
||||
|
@ -3,11 +3,8 @@
|
||||
# cspell:enableCompoundWords
|
||||
###########################################################
|
||||
|
||||
# use environment variables
|
||||
if [ "$BASE_URL" != "ROOT" ]; then
|
||||
mkdir -p "$(dirname "$WEBAPP_PATH/$BASE_URL")"
|
||||
mv "$WEBAPP_PATH/ROOT.war" "$WEBAPP_PATH/$BASE_URL.war"
|
||||
fi
|
||||
# ensure context path starts with a slash
|
||||
export CONTEXT_PATH="/${BASE_URL#'/'}"
|
||||
|
||||
# base image entrypoint
|
||||
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 |
6
examples/README.md
Normal file
@ -0,0 +1,6 @@
|
||||
# Examples
|
||||
|
||||
- [Additional fonts inside the PlantUML docker container](./additional-fonts)
|
||||
- [Nginx simple reverse proxy example](./nginx-simple)
|
||||
- [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
|
119
examples/nginx-contextpath/README.md
Normal file
@ -0,0 +1,119 @@
|
||||
# Nginx reverse proxy example with defined location directive
|
||||
|
||||
In this example, the reverse proxy is defined only under the `/plantuml` context path.
|
||||
All other context paths (locations) are not affected and are freely available.
|
||||
This allows the server to be used for more than "just" PlantUML.
|
||||
|
||||
References:
|
||||
- [Nginx documentation](https://nginx.org/en/docs/)
|
||||
- [Nginx beginner's guide](https://nginx.org/en/docs/beginners_guide.html)
|
||||
|
||||
|
||||
## Quick start
|
||||
|
||||
Be sure to have [`docker-compose.yml`](./docker-compose.yml) and [`nginx.conf`](./nginx.conf) inside your current working directory.
|
||||
|
||||
```bash
|
||||
# start nginx and plantuml server
|
||||
docker-compose up -d
|
||||
|
||||
# stop nginx and plantuml server
|
||||
docker-compose down
|
||||
```
|
||||
|
||||
Check with `docker ps` if both container are up and running:
|
||||
|
||||
```
|
||||
$ docker ps
|
||||
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
|
||||
217e753a0dcf plantuml/plantuml-server:jetty "/entrypoint.sh" 4 seconds ago Up 3 seconds 8080/tcp plantuml-server
|
||||
9b1290c100f5 nginx:alpine "/docker-entrypoint.…" 4 seconds ago Up 3 seconds 0.0.0.0:80->80/tcp, :::80->80/tcp nginx
|
||||
```
|
||||
|
||||
Open [http://localhost/plantuml](http://localhost/plantuml) inside your browser.
|
||||
YEAH! You are now using PlantUML behind a simple Nginx reverse proxy.
|
||||
|
||||
|
||||
## Nginx configuration
|
||||
|
||||
```nginx
|
||||
...
|
||||
|
||||
# PlantUML
|
||||
location /plantuml/ {
|
||||
proxy_pass http://plantuml-server:8080/plantuml/;
|
||||
}
|
||||
|
||||
...
|
||||
```
|
||||
|
||||
- `location /plantuml/` to reverse only the context path `/plantuml`
|
||||
- `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.
|
||||
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
|
||||
|
||||
```yaml
|
||||
version: "3"
|
||||
|
||||
services:
|
||||
plantuml-server:
|
||||
image: plantuml/plantuml-server:jetty
|
||||
container_name: plantuml-server
|
||||
environment:
|
||||
- TZ=Europe/Berlin
|
||||
- BASE_URL=plantuml
|
||||
|
||||
nginx:
|
||||
image: nginx:alpine
|
||||
container_name: nginx
|
||||
ports:
|
||||
- "80:80"
|
||||
environment:
|
||||
- TZ=Europe/Berlin
|
||||
volumes:
|
||||
- ./nginx.conf:/etc/nginx/nginx.conf:ro
|
||||
```
|
||||
|
||||
- Set `container_name` to use them instead of e.g. ip addresses
|
||||
- Set the environment `TZ` the ensure the same timezone.
|
||||
For example to server timezone (`cat /etc/timezone`)?
|
||||
- plantuml-server
|
||||
* plantuml-server already exposes port `8080` to it's own local network (but not outside).
|
||||
Since plantuml-server and nginx are sharing a network, nginx can reach plantuml-server without further settings.
|
||||
* Set the environment `BASE_URL` to the preferred context path
|
||||
- nginx
|
||||
* open/link port `80` to the outside
|
||||
* `./nginx.conf:/etc/nginx/nginx.conf:ro` to use your own Nginx configuration (readonly)
|
||||
|
||||
|
||||
## Useful commands
|
||||
|
||||
```bash
|
||||
# see whats going on inside your docker containers
|
||||
docker logs --tail 50 --follow --timestamps nginx
|
||||
docker logs --tail 50 --follow --timestamps plantuml-server
|
||||
```
|
19
examples/nginx-contextpath/docker-compose.yml
Normal file
@ -0,0 +1,19 @@
|
||||
version: "3"
|
||||
|
||||
services:
|
||||
plantuml-server:
|
||||
image: plantuml/plantuml-server:jetty
|
||||
container_name: plantuml-server
|
||||
environment:
|
||||
- TZ=Europe/Berlin
|
||||
- BASE_URL=plantuml
|
||||
|
||||
nginx:
|
||||
image: nginx:alpine
|
||||
container_name: nginx
|
||||
ports:
|
||||
- "80:80"
|
||||
environment:
|
||||
- TZ=Europe/Berlin
|
||||
volumes:
|
||||
- ./nginx.conf:/etc/nginx/nginx.conf:ro
|
44
examples/nginx-contextpath/nginx.conf
Normal file
@ -0,0 +1,44 @@
|
||||
user nginx;
|
||||
worker_processes auto;
|
||||
|
||||
error_log /var/log/nginx/error.log notice;
|
||||
pid /var/run/nginx.pid;
|
||||
|
||||
include /etc/nginx/modules-enabled/*.conf;
|
||||
|
||||
events {
|
||||
worker_connections 1024;
|
||||
}
|
||||
|
||||
http {
|
||||
|
||||
server {
|
||||
listen 80;
|
||||
server_name localhost;
|
||||
|
||||
# PlantUML
|
||||
location /plantuml/ {
|
||||
proxy_pass http://plantuml-server:8080/plantuml/;
|
||||
}
|
||||
}
|
||||
|
||||
client_max_body_size 0;
|
||||
|
||||
include /etc/nginx/mime.types;
|
||||
default_type application/octet-stream;
|
||||
|
||||
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
|
||||
'$status $body_bytes_sent "$http_referer" '
|
||||
'"$http_user_agent" "$http_x_forwarded_for"';
|
||||
|
||||
access_log /var/log/nginx/access.log main;
|
||||
|
||||
sendfile on;
|
||||
#tcp_nopush on;
|
||||
|
||||
keepalive_timeout 65;
|
||||
|
||||
#gzip on;
|
||||
|
||||
include /etc/nginx/conf.d/*.conf;
|
||||
}
|
97
examples/nginx-simple/README.md
Normal file
@ -0,0 +1,97 @@
|
||||
# Nginx simple reverse proxy example
|
||||
|
||||
References:
|
||||
- [Nginx documentation](https://nginx.org/en/docs/)
|
||||
- [Nginx beginner's guide](https://nginx.org/en/docs/beginners_guide.html)
|
||||
|
||||
|
||||
## Quick start
|
||||
|
||||
Be sure to have [`docker-compose.yml`](./docker-compose.yml) and [`nginx.conf`](./nginx.conf) inside your current working directory.
|
||||
|
||||
```bash
|
||||
# start nginx and plantuml server
|
||||
docker-compose up -d
|
||||
|
||||
# stop nginx and plantuml server
|
||||
docker-compose down
|
||||
```
|
||||
|
||||
Check with `docker ps` if both container are up and running:
|
||||
|
||||
```
|
||||
$ docker ps
|
||||
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
|
||||
217e753a0dcf plantuml/plantuml-server:jetty "/entrypoint.sh" 4 seconds ago Up 3 seconds 8080/tcp plantuml-server
|
||||
9b1290c100f5 nginx:alpine "/docker-entrypoint.…" 4 seconds ago Up 3 seconds 0.0.0.0:80->80/tcp, :::80->80/tcp nginx
|
||||
```
|
||||
|
||||
Open [http://localhost](http://localhost) inside your browser.
|
||||
YEAH! You are now using PlantUML behind a simple Nginx reverse proxy.
|
||||
|
||||
|
||||
## Nginx configuration
|
||||
|
||||
```nginx
|
||||
...
|
||||
|
||||
# PlantUML
|
||||
location / {
|
||||
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/;
|
||||
}
|
||||
|
||||
...
|
||||
```
|
||||
|
||||
- `location /` to reverse complete server
|
||||
- `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/` to set reverse proxy path to plantuml server.
|
||||
Use the docker container name `plantuml-server` instead of ip addresses.
|
||||
|
||||
|
||||
## Nginx and PlantUML server
|
||||
|
||||
```yaml
|
||||
version: "3"
|
||||
|
||||
services:
|
||||
plantuml-server:
|
||||
image: plantuml/plantuml-server:jetty
|
||||
container_name: plantuml-server
|
||||
environment:
|
||||
- TZ=Europe/Berlin
|
||||
|
||||
nginx:
|
||||
image: nginx:alpine
|
||||
container_name: nginx
|
||||
ports:
|
||||
- "80:80"
|
||||
environment:
|
||||
- TZ=Europe/Berlin
|
||||
volumes:
|
||||
- ./nginx.conf:/etc/nginx/nginx.conf:ro
|
||||
```
|
||||
|
||||
- Set `container_name` to use them instead of e.g. ip addresses
|
||||
- Set the environment `TZ` the ensure the same timezone.
|
||||
For example to server timezone (`cat /etc/timezone`)?
|
||||
- plantuml-server
|
||||
* plantuml-server already exposes port `8080` to it's own local network (but not outside).
|
||||
Since plantuml-server and nginx are sharing a network, nginx can reach plantuml-server without further settings.
|
||||
- nginx
|
||||
* open/link port `80` to the outside
|
||||
* `./nginx.conf:/etc/nginx/nginx.conf:ro` to use your own Nginx configuration (readonly)
|
||||
|
||||
|
||||
## Useful commands
|
||||
|
||||
```bash
|
||||
# see whats going on inside your docker containers
|
||||
docker logs --tail 50 --follow --timestamps nginx
|
||||
docker logs --tail 50 --follow --timestamps plantuml-server
|
||||
```
|
18
examples/nginx-simple/docker-compose.yml
Normal file
@ -0,0 +1,18 @@
|
||||
version: "3"
|
||||
|
||||
services:
|
||||
plantuml-server:
|
||||
image: plantuml/plantuml-server:jetty
|
||||
container_name: plantuml-server
|
||||
environment:
|
||||
- TZ=Europe/Berlin
|
||||
|
||||
nginx:
|
||||
image: nginx:alpine
|
||||
container_name: nginx
|
||||
ports:
|
||||
- "80:80"
|
||||
environment:
|
||||
- TZ=Europe/Berlin
|
||||
volumes:
|
||||
- ./nginx.conf:/etc/nginx/nginx.conf:ro
|
48
examples/nginx-simple/nginx.conf
Normal file
@ -0,0 +1,48 @@
|
||||
user nginx;
|
||||
worker_processes auto;
|
||||
|
||||
error_log /var/log/nginx/error.log notice;
|
||||
pid /var/run/nginx.pid;
|
||||
|
||||
include /etc/nginx/modules-enabled/*.conf;
|
||||
|
||||
events {
|
||||
worker_connections 1024;
|
||||
}
|
||||
|
||||
http {
|
||||
|
||||
server {
|
||||
listen 80;
|
||||
server_name localhost;
|
||||
|
||||
# PlantUML
|
||||
location / {
|
||||
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/;
|
||||
}
|
||||
}
|
||||
|
||||
client_max_body_size 0;
|
||||
|
||||
include /etc/nginx/mime.types;
|
||||
default_type application/octet-stream;
|
||||
|
||||
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
|
||||
'$status $body_bytes_sent "$http_referer" '
|
||||
'"$http_user_agent" "$http_x_forwarded_for"';
|
||||
|
||||
access_log /var/log/nginx/access.log main;
|
||||
|
||||
sendfile on;
|
||||
#tcp_nopush on;
|
||||
|
||||
keepalive_timeout 65;
|
||||
|
||||
#gzip on;
|
||||
|
||||
include /etc/nginx/conf.d/*.conf;
|
||||
}
|
451
pom.jdk8.xml
@ -6,112 +6,30 @@
|
||||
>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>org.sourceforge.plantuml</groupId>
|
||||
<parent>
|
||||
<groupId>org.sourceforge.plantuml</groupId>
|
||||
<artifactId>plantumlservlet-parent</artifactId>
|
||||
<version>1-SNAPSHOT</version>
|
||||
<relativePath>pom.parent.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<artifactId>plantumlservlet</artifactId>
|
||||
<version>1-SNAPSHOT</version>
|
||||
<packaging>war</packaging>
|
||||
|
||||
<name>PlantUML Servlet</name>
|
||||
<url>https://plantuml.github.io/plantuml-server/index.html</url>
|
||||
|
||||
<properties>
|
||||
<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.2021.14</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>
|
||||
<slf4j.version>1.7.32</slf4j.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>
|
||||
<!-- Logging -->
|
||||
<slf4j-log4j12.version>${slf4j.version}</slf4j-log4j12.version>
|
||||
<slf4j-api.version>${slf4j.version}</slf4j-api.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>
|
||||
<!-- no JDK8 support starting version 10.0.0 -->
|
||||
<checkstyle.version>9.3</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>
|
||||
<!-- no JDK8 support starting version 2.5.0 -->
|
||||
<resources-optimizer-maven-plugin.version>2.4.4</resources-optimizer-maven-plugin.version>
|
||||
</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>jakarta.servlet</groupId>
|
||||
<artifactId>jakarta.servlet-api</artifactId>
|
||||
@ -146,53 +64,8 @@
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</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>
|
||||
<!-- Logging -->
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-log4j12</artifactId>
|
||||
<version>${slf4j-log4j12.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-api</artifactId>
|
||||
<version>${slf4j-api.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>
|
||||
@ -206,304 +79,4 @@
|
||||
</exclusions>
|
||||
</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>
|
||||
|
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>
|
475
pom.xml
@ -6,476 +6,17 @@
|
||||
>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>org.sourceforge.plantuml</groupId>
|
||||
<artifactId>plantumlservlet</artifactId>
|
||||
<version>1-SNAPSHOT</version>
|
||||
<packaging>war</packaging>
|
||||
<parent>
|
||||
<groupId>org.sourceforge.plantuml</groupId>
|
||||
<artifactId>plantumlservlet-parent</artifactId>
|
||||
<version>1-SNAPSHOT</version>
|
||||
<relativePath>pom.parent.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<name>PlantUML Servlet</name>
|
||||
<url>https://plantuml.github.io/plantuml-server/index.html</url>
|
||||
<artifactId>plantumlservlet</artifactId>
|
||||
<packaging>war</packaging>
|
||||
|
||||
<properties>
|
||||
<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.2021.14</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>
|
||||
<slf4j.version>1.7.32</slf4j.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>
|
||||
<!-- Logging -->
|
||||
<slf4j-log4j12.version>${slf4j.version}</slf4j-log4j12.version>
|
||||
<slf4j-api.version>${slf4j.version}</slf4j-api.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>
|
||||
|
||||
<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>
|
||||
<!-- Logging -->
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-log4j12</artifactId>
|
||||
<version>${slf4j-log4j12.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-api</artifactId>
|
||||
<version>${slf4j-api.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>
|
||||
|
Before Width: | Height: | Size: 46 KiB |
@ -15,6 +15,8 @@
|
||||
<module name="LineLength">
|
||||
<property name="max" value="120" />
|
||||
<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 name="NewlineAtEndOfFile">
|
||||
<metadata name="net.sf.eclipsecs.core.lastEnabledSeverity" value="inherit" />
|
||||
@ -25,6 +27,7 @@
|
||||
<property name="message" value="Line has trailing spaces." />
|
||||
</module>
|
||||
<module name="Translation" />
|
||||
<module name="SuppressWarningsFilter" />
|
||||
<module name="TreeWalker">
|
||||
<module name="ArrayTypeStyle" />
|
||||
<module name="AvoidInlineConditionals">
|
||||
@ -113,5 +116,6 @@
|
||||
<module name="VisibilityModifier" />
|
||||
<module name="WhitespaceAfter" />
|
||||
<module name="WhitespaceAround" />
|
||||
<module name="SuppressWarningsHolder" />
|
||||
</module>
|
||||
</module>
|
||||
|
@ -64,7 +64,8 @@
|
||||
</Array>
|
||||
</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>
|
||||
</New>
|
||||
|
||||
|
@ -14,6 +14,7 @@
|
||||
<ignoreVersion type="regex">(?i).*RC(?:-?\d+)?</ignoreVersion>
|
||||
<ignoreVersion type="regex">(?i).*CR(?:-?\d+)?</ignoreVersion>
|
||||
<ignoreVersion type="regex">(?i).*M(?:-?\d+)?</ignoreVersion>
|
||||
<ignoreVersion type="regex">(?i).*-dev((?:-?\d+)|(?:\.20\d{6}))?</ignoreVersion>
|
||||
</ignoreVersions>
|
||||
<rules>
|
||||
<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;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
@ -38,14 +40,16 @@ import net.sourceforge.plantuml.ErrorUml;
|
||||
import net.sourceforge.plantuml.FileFormat;
|
||||
import net.sourceforge.plantuml.FileFormatOption;
|
||||
import net.sourceforge.plantuml.NullOutputStream;
|
||||
import net.sourceforge.plantuml.OptionFlags;
|
||||
import net.sourceforge.plantuml.SourceStringReader;
|
||||
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.DiagramDescription;
|
||||
import net.sourceforge.plantuml.core.ImageData;
|
||||
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;
|
||||
|
||||
/**
|
||||
@ -54,27 +58,33 @@ import net.sourceforge.plantuml.version.Version;
|
||||
*/
|
||||
public class DiagramResponse {
|
||||
|
||||
/**
|
||||
* {@link FileFormat} to http content type mapping.
|
||||
*/
|
||||
private static final Map<FileFormat, String> CONTENT_TYPE;
|
||||
private static class BlockSelection {
|
||||
private final BlockUml block;
|
||||
private final int systemIdx;
|
||||
|
||||
BlockSelection(BlockUml blk, int idx) {
|
||||
block = blk;
|
||||
systemIdx = idx;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* X-Powered-By http header value included in every response by default.
|
||||
*/
|
||||
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 {
|
||||
OptionFlags.ALLOW_INCLUDE = false;
|
||||
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");
|
||||
}});
|
||||
init();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -103,6 +113,42 @@ public class DiagramResponse {
|
||||
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.
|
||||
*
|
||||
@ -114,7 +160,17 @@ public class DiagramResponse {
|
||||
public void sendDiagram(String uml, int idx) throws IOException {
|
||||
response.addHeader("Access-Control-Allow-Origin", "*");
|
||||
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) {
|
||||
byte[] imageBytes;
|
||||
try (ByteArrayOutputStream outstream = new ByteArrayOutputStream()) {
|
||||
@ -126,20 +182,86 @@ public class DiagramResponse {
|
||||
response.getOutputStream().write(encodedBytes.getBytes());
|
||||
return;
|
||||
}
|
||||
final BlockUml blockUml = reader.getBlocks().get(0);
|
||||
if (notModified(blockUml)) {
|
||||
addHeaderForCache(blockUml);
|
||||
|
||||
final BlockSelection blockSelection = getOutputBlockSelection(reader, idx);
|
||||
if (blockSelection == null) {
|
||||
response.sendError(HttpServletResponse.SC_BAD_REQUEST);
|
||||
return;
|
||||
}
|
||||
|
||||
if (notModified(blockSelection.block)) {
|
||||
addHeaderForCache(blockSelection.block);
|
||||
response.sendError(HttpServletResponse.SC_NOT_MODIFIED);
|
||||
return;
|
||||
}
|
||||
if (StringUtils.isDiagramCacheable(uml)) {
|
||||
addHeaderForCache(blockUml);
|
||||
addHeaderForCache(blockSelection.block);
|
||||
}
|
||||
final Diagram diagram = blockUml.getDiagram();
|
||||
final Diagram diagram = blockSelection.block.getDiagram();
|
||||
if (diagram instanceof PSystemError) {
|
||||
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
|
||||
*/
|
||||
public void sendMap(String uml, int idx) throws IOException {
|
||||
if (idx < 0) {
|
||||
idx = 0;
|
||||
}
|
||||
response.addHeader("Access-Control-Allow-Origin", "*");
|
||||
response.setContentType(getContentType());
|
||||
SourceStringReader reader = new SourceStringReader(uml);
|
||||
final BlockUml blockUml = reader.getBlocks().get(0);
|
||||
if (StringUtils.isDiagramCacheable(uml)) {
|
||||
addHeaderForCache(blockUml);
|
||||
|
||||
if (idx < 0) {
|
||||
response.sendError(HttpServletResponse.SC_BAD_REQUEST, String.format("Invalid diagram index: {0}", idx));
|
||||
return;
|
||||
}
|
||||
final Diagram diagram = blockUml.getDiagram();
|
||||
ImageData map = diagram.exportDiagram(new NullOutputStream(), idx,
|
||||
new FileFormatOption(FileFormat.PNG, false));
|
||||
final SourceStringReader reader = getSourceStringReader(uml);
|
||||
if (reader == null) {
|
||||
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()) {
|
||||
PrintWriter httpOut = response.getWriter();
|
||||
final String cmap = map.getCMapData("plantuml");
|
||||
@ -253,7 +393,7 @@ public class DiagramResponse {
|
||||
* @return response content type
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
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
|
||||
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);
|
||||
if (!proxyMatcher.matches()) {
|
||||
// Bad URI format.
|
||||
response.setStatus(400);
|
||||
response.sendError(HttpServletResponse.SC_BAD_REQUEST, "URL malformed.");
|
||||
return;
|
||||
}
|
||||
|
||||
String num = proxyMatcher.group(2); // Optional number of the diagram source
|
||||
String format = proxyMatcher.group(4); // Expected format of the generated diagram
|
||||
String sourceURL = proxyMatcher.group(5);
|
||||
if (ProxyServlet.forbiddenURL(sourceURL)) {
|
||||
response.sendError(HttpServletResponse.SC_BAD_REQUEST, "Forbidden URL format.");
|
||||
return;
|
||||
}
|
||||
|
||||
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.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import javax.net.ssl.HttpsURLConnection;
|
||||
|
||||
import jakarta.servlet.RequestDispatcher;
|
||||
import jakarta.servlet.ServletException;
|
||||
import jakarta.servlet.http.HttpServlet;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
|
||||
import net.sourceforge.plantuml.OptionFlags;
|
||||
import net.sourceforge.plantuml.api.PlantumlUtils;
|
||||
import net.sourceforge.plantuml.code.Transcoder;
|
||||
import net.sourceforge.plantuml.code.TranscoderUtil;
|
||||
import net.sourceforge.plantuml.code.NoPlantumlCompressionException;
|
||||
import net.sourceforge.plantuml.png.MetadataTag;
|
||||
import net.sourceforge.plantuml.servlet.utility.Configuration;
|
||||
import net.sourceforge.plantuml.servlet.utility.UmlExtractor;
|
||||
@ -58,7 +52,13 @@ import net.sourceforge.plantuml.servlet.utility.UrlDataExtractor;
|
||||
* Modified by Maxime Sinclair
|
||||
*/
|
||||
@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.
|
||||
@ -66,16 +66,54 @@ public class PlantUmlServlet extends HttpServlet {
|
||||
*/
|
||||
private static final String DEFAULT_ENCODED_TEXT = "SyfFKj2rKt3CoKnELR1Io4ZDoSa70000";
|
||||
|
||||
/**
|
||||
* 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\\-\\_]+)");
|
||||
@Override
|
||||
protected String getServletContextPath() {
|
||||
return "uml";
|
||||
}
|
||||
|
||||
static {
|
||||
OptionFlags.ALLOW_INCLUDE = false;
|
||||
if ("true".equalsIgnoreCase(System.getenv("ALLOW_PLANTUML_INCLUDE"))) {
|
||||
OptionFlags.ALLOW_INCLUDE = true;
|
||||
/**
|
||||
* Encode arbitrary string to HTML string.
|
||||
*
|
||||
* @param string arbitrary string
|
||||
*
|
||||
* @return html encoded string
|
||||
*/
|
||||
public static String stringToHTMLString(String string) {
|
||||
final StringBuilder sb = new StringBuilder(string.length());
|
||||
// true if last char was blank
|
||||
final int length = string.length();
|
||||
int offset = 0;
|
||||
while (offset < length) {
|
||||
final int c = string.codePointAt(offset);
|
||||
if (c == ' ') {
|
||||
sb.append(' ');
|
||||
} else if (c == '"') {
|
||||
sb.append(""");
|
||||
} else if (c == '&') {
|
||||
sb.append("&");
|
||||
} else if (c == '<') {
|
||||
sb.append("<");
|
||||
} else if (c == '>') {
|
||||
sb.append(">");
|
||||
} else if (c == '\r') {
|
||||
sb.append("\r");
|
||||
} else if (c == '\n') {
|
||||
sb.append("\n");
|
||||
} else {
|
||||
int ci = 0xffffff & c;
|
||||
if (ci < 160) {
|
||||
// nothing special only 7 Bit
|
||||
sb.append((char) c);
|
||||
} else {
|
||||
// Not 7 Bit use the unicode system
|
||||
sb.append("&#");
|
||||
sb.append(ci);
|
||||
sb.append(';');
|
||||
}
|
||||
}
|
||||
offset += Character.charCount(c);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -95,8 +133,15 @@ public class PlantUmlServlet extends HttpServlet {
|
||||
final int idx = UrlDataExtractor.getIndex(request.getRequestURI());
|
||||
|
||||
// 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);
|
||||
final RequestDispatcher dispatcher = request.getRequestDispatcher("/index.jsp");
|
||||
final RequestDispatcher dispatcher = request.getRequestDispatcher(path);
|
||||
dispatcher.forward(request, response);
|
||||
}
|
||||
|
||||
@ -144,6 +189,10 @@ public class PlantUmlServlet extends HttpServlet {
|
||||
if (text != null && !text.isEmpty()) {
|
||||
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) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
@ -177,26 +226,7 @@ public class PlantUmlServlet extends HttpServlet {
|
||||
* @throws IOException if an input or output exception occurred
|
||||
*/
|
||||
private String getTextFromUrl(HttpServletRequest request) throws IOException {
|
||||
// textual diagram source from request URI
|
||||
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 "";
|
||||
return getTranscoder().decode(getEncodedTextFromUrl(request));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -209,28 +239,16 @@ public class PlantUmlServlet extends HttpServlet {
|
||||
*/
|
||||
private void prepareRequestForDispatch(HttpServletRequest request, String text, int idx) throws IOException {
|
||||
final String encoded = getTranscoder().encode(text);
|
||||
final String index = (idx < 0) ? "" : idx + "/";
|
||||
// diagram sources
|
||||
request.setAttribute("encoded", encoded);
|
||||
request.setAttribute("decoded", text);
|
||||
request.setAttribute("index", idx);
|
||||
request.setAttribute("index", (idx < 0) ? "" : idx);
|
||||
// properties
|
||||
request.setAttribute("showSocialButtons", Configuration.get("SHOW_SOCIAL_BUTTONS"));
|
||||
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
|
||||
final boolean hasMap = PlantumlUtils.hasCMapData(text);
|
||||
request.setAttribute("hasMap", hasMap);
|
||||
String map = "";
|
||||
if (hasMap) {
|
||||
if (PlantumlUtils.hasCMapData(text)) {
|
||||
try {
|
||||
map = UmlExtractor.extractMap(text);
|
||||
} catch (Exception e) {
|
||||
@ -240,33 +258,6 @@ public class PlantUmlServlet extends HttpServlet {
|
||||
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.
|
||||
*
|
||||
@ -300,23 +291,13 @@ public class PlantUmlServlet extends HttpServlet {
|
||||
String encoded,
|
||||
Integer index
|
||||
) throws IOException {
|
||||
final String result;
|
||||
final String path;
|
||||
if (index == null || index < 0) {
|
||||
result = request.getContextPath() + "/uml/" + encoded;
|
||||
path = request.getContextPath() + "/uml/" + encoded;
|
||||
} else {
|
||||
result = request.getContextPath() + "/uml/" + index + "/" + encoded;
|
||||
path = request.getContextPath() + "/uml/" + index + "/" + encoded;
|
||||
}
|
||||
|
||||
response.sendRedirect(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get PlantUML transcoder.
|
||||
*
|
||||
* @return transcoder instance
|
||||
*/
|
||||
private Transcoder getTranscoder() {
|
||||
return TranscoderUtil.getDefaultTranscoder();
|
||||
response.sendRedirect(path);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -333,7 +314,6 @@ public class PlantUmlServlet extends HttpServlet {
|
||||
HttpsURLConnection con = (HttpsURLConnection) url.openConnection();
|
||||
con.setRequestMethod("GET");
|
||||
con.setReadTimeout(10000); // 10 seconds
|
||||
// printHttpsCert(con);
|
||||
con.connect();
|
||||
return con;
|
||||
} 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.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.security.cert.Certificate;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.imageio.IIOException;
|
||||
import javax.net.ssl.HttpsURLConnection;
|
||||
import javax.net.ssl.SSLPeerUnverifiedException;
|
||||
|
||||
import jakarta.servlet.ServletException;
|
||||
import jakarta.servlet.http.HttpServlet;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
|
||||
import net.sourceforge.plantuml.BlockUml;
|
||||
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.
|
||||
@ -56,49 +48,86 @@ import net.sourceforge.plantuml.core.UmlSource;
|
||||
@SuppressWarnings("SERIAL")
|
||||
public class ProxyServlet extends HttpServlet {
|
||||
|
||||
static {
|
||||
OptionFlags.ALLOW_INCLUDE = false;
|
||||
if ("true".equalsIgnoreCase(System.getenv("ALLOW_PLANTUML_INCLUDE"))) {
|
||||
OptionFlags.ALLOW_INCLUDE = true;
|
||||
public static boolean forbiddenURL(String full) {
|
||||
if (full == null) {
|
||||
return 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
|
||||
public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
|
||||
|
||||
final String fmt = request.getParameter("fmt");
|
||||
final String source = request.getParameter("src");
|
||||
final String index = request.getParameter("idx");
|
||||
final URL srcUrl;
|
||||
// Check if the src URL is valid
|
||||
try {
|
||||
srcUrl = new URL(source);
|
||||
} catch (MalformedURLException mue) {
|
||||
mue.printStackTrace();
|
||||
response.setStatus(400);
|
||||
return;
|
||||
|
||||
final int idx = index == null ? 0 : Integer.parseInt(index);
|
||||
final URL srcUrl = validateURL(source, response);
|
||||
if (srcUrl == null) {
|
||||
return; // error is already set/handled inside `validateURL`
|
||||
}
|
||||
|
||||
// generate the response
|
||||
String diagmarkup = 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);
|
||||
// fetch diagram from URL
|
||||
final String uml = getSource(srcUrl);
|
||||
|
||||
// generate the response
|
||||
DiagramResponse dr = new DiagramResponse(response, getOutputFormat(fmt), request);
|
||||
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) {
|
||||
// Browser has closed the connection, so the HTTP OutputStream is closed
|
||||
// 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
|
||||
*/
|
||||
private String getSource(final URL url) throws IOException {
|
||||
String line;
|
||||
BufferedReader rd;
|
||||
StringBuilder sb;
|
||||
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;
|
||||
HttpURLConnection conn = getConnection(url);
|
||||
try (BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream()))) {
|
||||
return br.lines().collect(Collectors.joining("\n"));
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
/**
|
||||
@ -144,19 +158,16 @@ public class ProxyServlet extends HttpServlet {
|
||||
if (format == null) {
|
||||
return FileFormat.PNG;
|
||||
}
|
||||
if (format.equals("svg")) {
|
||||
return FileFormat.SVG;
|
||||
switch (format.toLowerCase()) {
|
||||
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
|
||||
*/
|
||||
private HttpURLConnection getConnection(final URL url) throws IOException {
|
||||
final HttpURLConnection con = (HttpURLConnection) url.openConnection();
|
||||
//if (con instanceof HttpsURLConnection) {
|
||||
// printHttpsCert((HttpsURLConnection) con);
|
||||
//}
|
||||
con.setRequestMethod("GET");
|
||||
public static HttpURLConnection getConnection(final URL url) throws IOException {
|
||||
final HttpURLConnection conn = (HttpURLConnection) url.openConnection();
|
||||
conn.setRequestMethod("GET");
|
||||
String token = System.getenv("HTTP_AUTHORIZATION");
|
||||
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 net.sourceforge.plantuml.FileFormat;
|
||||
import net.sourceforge.plantuml.OptionFlags;
|
||||
import net.sourceforge.plantuml.servlet.utility.UmlExtractor;
|
||||
import net.sourceforge.plantuml.servlet.utility.UrlDataExtractor;
|
||||
|
||||
@ -44,13 +43,6 @@ import net.sourceforge.plantuml.servlet.utility.UrlDataExtractor;
|
||||
@SuppressWarnings("SERIAL")
|
||||
public abstract class UmlDiagramService extends HttpServlet {
|
||||
|
||||
static {
|
||||
OptionFlags.ALLOW_INCLUDE = false;
|
||||
if ("true".equalsIgnoreCase(System.getenv("ALLOW_PLANTUML_INCLUDE"))) {
|
||||
OptionFlags.ALLOW_INCLUDE = true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
|
||||
final String url = request.getRequestURI();
|
||||
|
@ -29,7 +29,6 @@ import java.net.URLDecoder;
|
||||
|
||||
import net.sourceforge.plantuml.FileFormat;
|
||||
import net.sourceforge.plantuml.FileFormatOption;
|
||||
import net.sourceforge.plantuml.OptionFlags;
|
||||
import net.sourceforge.plantuml.SourceStringReader;
|
||||
import net.sourceforge.plantuml.code.Transcoder;
|
||||
import net.sourceforge.plantuml.code.TranscoderUtil;
|
||||
@ -42,13 +41,6 @@ import net.sourceforge.plantuml.core.ImageData;
|
||||
*/
|
||||
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
|
||||
* HTTP URI.
|
||||
|
@ -1,219 +1,255 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<web-app
|
||||
xmlns="https://jakarta.ee/xml/ns/jakartaee"
|
||||
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:web="https://jakarta.ee/xml/ns/jakartaee/web-app_5_0.xsd"
|
||||
xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/web-app_5_0.xsd"
|
||||
version="5.0"
|
||||
>
|
||||
|
||||
<!-- ========================================================== -->
|
||||
<!-- General -->
|
||||
<!-- ========================================================== -->
|
||||
|
||||
<!-- Name the application -->
|
||||
<display-name>PlantUML</display-name>
|
||||
<description>PlantUML Online Server</description>
|
||||
|
||||
<!-- This app is cluster-ready -->
|
||||
<distributable />
|
||||
|
||||
<!-- Set timeout to 120 minutes -->
|
||||
<session-config>
|
||||
<session-timeout>120</session-timeout>
|
||||
</session-config>
|
||||
|
||||
|
||||
<!-- ========================================================== -->
|
||||
<!-- Custom Tag Libraries -->
|
||||
<!-- ========================================================== -->
|
||||
|
||||
<!-- Taglib declarations are no longer required since JSP 2.0, see Removing taglib from web.xml -->
|
||||
<!-- The <taglib> did not need to be a child of <jsp-config> in earlier versions but is required as of Tomcat 7 -->
|
||||
<!-- Note that you can only have one <jsp-config> element per web.xml -->
|
||||
<!--
|
||||
<jsp-config>
|
||||
<taglib>
|
||||
<taglib-uri>http://java.sun.com/jsp/jstl/core</taglib-uri>
|
||||
<taglib-location>/WEB-INF/lib/c.tld</taglib-location>
|
||||
</taglib>
|
||||
</jsp-config>
|
||||
-->
|
||||
|
||||
|
||||
<!-- ========================================================== -->
|
||||
<!-- Context Parameters -->
|
||||
<!-- ========================================================== -->
|
||||
|
||||
<context-param>
|
||||
<param-name>org.eclipse.jetty.servlet.Default.welcomeServlets</param-name>
|
||||
<param-value>exact</param-value>
|
||||
</context-param>
|
||||
|
||||
|
||||
<!-- ========================================================== -->
|
||||
<!-- Servlets -->
|
||||
<!-- ========================================================== -->
|
||||
|
||||
<servlet>
|
||||
<servlet-name>jsp</servlet-name>
|
||||
<servlet-class>org.eclipse.jetty.jsp.JettyJspServlet</servlet-class>
|
||||
<init-param>
|
||||
<param-name>compilerSourceVM</param-name>
|
||||
<param-value>1.7</param-value>
|
||||
</init-param>
|
||||
<init-param>
|
||||
<param-name>compilerTargetVM</param-name>
|
||||
<param-value>1.7</param-value>
|
||||
</init-param>
|
||||
</servlet>
|
||||
|
||||
<servlet>
|
||||
<servlet-name>plantumlservlet</servlet-name>
|
||||
<servlet-class>net.sourceforge.plantuml.servlet.PlantUmlServlet</servlet-class>
|
||||
</servlet>
|
||||
<servlet-mapping>
|
||||
<servlet-name>plantumlservlet</servlet-name>
|
||||
<url-pattern>/welcome</url-pattern>
|
||||
</servlet-mapping>
|
||||
<servlet-mapping>
|
||||
<servlet-name>plantumlservlet</servlet-name>
|
||||
<url-pattern>/uml/*</url-pattern>
|
||||
</servlet-mapping>
|
||||
<servlet-mapping>
|
||||
<servlet-name>plantumlservlet</servlet-name>
|
||||
<url-pattern>/form</url-pattern>
|
||||
</servlet-mapping>
|
||||
<servlet-mapping>
|
||||
<servlet-name>plantumlservlet</servlet-name>
|
||||
<url-pattern>/start/*</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<servlet>
|
||||
<servlet-name>imgservlet</servlet-name>
|
||||
<servlet-class>net.sourceforge.plantuml.servlet.ImgServlet</servlet-class>
|
||||
</servlet>
|
||||
<servlet-mapping>
|
||||
<servlet-name>imgservlet</servlet-name>
|
||||
<url-pattern>/png/*</url-pattern>
|
||||
</servlet-mapping>
|
||||
<servlet-mapping>
|
||||
<servlet-name>imgservlet</servlet-name>
|
||||
<url-pattern>/img/*</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<servlet>
|
||||
<servlet-name>svgservlet</servlet-name>
|
||||
<servlet-class>net.sourceforge.plantuml.servlet.SvgServlet</servlet-class>
|
||||
</servlet>
|
||||
<servlet-mapping>
|
||||
<servlet-name>svgservlet</servlet-name>
|
||||
<url-pattern>/svg/*</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<servlet>
|
||||
<servlet-name>epsservlet</servlet-name>
|
||||
<servlet-class>net.sourceforge.plantuml.servlet.EpsServlet</servlet-class>
|
||||
</servlet>
|
||||
<servlet-mapping>
|
||||
<servlet-name>epsservlet</servlet-name>
|
||||
<url-pattern>/eps/*</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<servlet>
|
||||
<servlet-name>epstextservlet</servlet-name>
|
||||
<servlet-class>net.sourceforge.plantuml.servlet.EpsTextServlet</servlet-class>
|
||||
</servlet>
|
||||
<servlet-mapping>
|
||||
<servlet-name>epstextservlet</servlet-name>
|
||||
<url-pattern>/epstext/*</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<servlet>
|
||||
<servlet-name>base64servlet</servlet-name>
|
||||
<servlet-class>net.sourceforge.plantuml.servlet.Base64Servlet</servlet-class>
|
||||
</servlet>
|
||||
<servlet-mapping>
|
||||
<servlet-name>base64servlet</servlet-name>
|
||||
<url-pattern>/base64/*</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<servlet>
|
||||
<servlet-name>asciiservlet</servlet-name>
|
||||
<servlet-class>net.sourceforge.plantuml.servlet.AsciiServlet</servlet-class>
|
||||
</servlet>
|
||||
<servlet-mapping>
|
||||
<servlet-name>asciiservlet</servlet-name>
|
||||
<url-pattern>/txt/*</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<servlet>
|
||||
<servlet-name>proxyservlet</servlet-name>
|
||||
<servlet-class>net.sourceforge.plantuml.servlet.ProxyServlet</servlet-class>
|
||||
</servlet>
|
||||
<servlet-mapping>
|
||||
<servlet-name>proxyservlet</servlet-name>
|
||||
<url-pattern>/proxy</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<servlet>
|
||||
<servlet-name>oldproxyservlet</servlet-name>
|
||||
<servlet-class>net.sourceforge.plantuml.servlet.OldProxyServlet</servlet-class>
|
||||
</servlet>
|
||||
<servlet-mapping>
|
||||
<servlet-name>oldproxyservlet</servlet-name>
|
||||
<url-pattern>/proxy/*</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<servlet>
|
||||
<servlet-name>mapservlet</servlet-name>
|
||||
<servlet-class>net.sourceforge.plantuml.servlet.MapServlet</servlet-class>
|
||||
</servlet>
|
||||
<servlet-mapping>
|
||||
<servlet-name>mapservlet</servlet-name>
|
||||
<url-pattern>/map/*</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<servlet>
|
||||
<servlet-name>checkservlet</servlet-name>
|
||||
<servlet-class>net.sourceforge.plantuml.servlet.CheckSyntaxServlet</servlet-class>
|
||||
</servlet>
|
||||
<servlet-mapping>
|
||||
<servlet-name>checkservlet</servlet-name>
|
||||
<url-pattern>/check/*</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<servlet>
|
||||
<servlet-name>languageservlet</servlet-name>
|
||||
<servlet-class>net.sourceforge.plantuml.servlet.LanguageServlet</servlet-class>
|
||||
</servlet>
|
||||
<servlet-mapping>
|
||||
<servlet-name>languageservlet</servlet-name>
|
||||
<url-pattern>/language</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
|
||||
<!-- ========================================================== -->
|
||||
<!-- Error Handler -->
|
||||
<!-- ========================================================== -->
|
||||
|
||||
<error-page>
|
||||
<exception-type>java.lang.Throwable</exception-type>
|
||||
<location>/error.jsp</location>
|
||||
</error-page>
|
||||
|
||||
<error-page>
|
||||
<error-code>500</error-code>
|
||||
<location>/error.jsp</location>
|
||||
</error-page>
|
||||
|
||||
|
||||
<!-- ========================================================== -->
|
||||
<!-- Welcome Files -->
|
||||
<!-- ========================================================== -->
|
||||
|
||||
<welcome-file-list>
|
||||
<welcome-file>welcome</welcome-file>
|
||||
</welcome-file-list>
|
||||
|
||||
</web-app>
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<web-app
|
||||
xmlns="https://jakarta.ee/xml/ns/jakartaee"
|
||||
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:web="https://jakarta.ee/xml/ns/jakartaee/web-app_5_0.xsd"
|
||||
xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/web-app_5_0.xsd"
|
||||
version="5.0"
|
||||
>
|
||||
|
||||
<!-- ========================================================== -->
|
||||
<!-- General -->
|
||||
<!-- ========================================================== -->
|
||||
|
||||
<!-- Name the application -->
|
||||
<display-name>PlantUML</display-name>
|
||||
<description>PlantUML Online Server</description>
|
||||
|
||||
<!-- This app is cluster-ready -->
|
||||
<distributable />
|
||||
|
||||
<!-- Set timeout to 120 minutes -->
|
||||
<session-config>
|
||||
<session-timeout>120</session-timeout>
|
||||
</session-config>
|
||||
|
||||
|
||||
<!-- ========================================================== -->
|
||||
<!-- Custom Tag Libraries -->
|
||||
<!-- ========================================================== -->
|
||||
|
||||
<!-- Taglib declarations are no longer required since JSP 2.0, see Removing taglib from web.xml -->
|
||||
<!-- The <taglib> did not need to be a child of <jsp-config> in earlier versions but is required as of Tomcat 7 -->
|
||||
<!-- Note that you can only have one <jsp-config> element per web.xml -->
|
||||
<!--
|
||||
<jsp-config>
|
||||
<taglib>
|
||||
<taglib-uri>http://java.sun.com/jsp/jstl/core</taglib-uri>
|
||||
<taglib-location>/WEB-INF/lib/c.tld</taglib-location>
|
||||
</taglib>
|
||||
</jsp-config>
|
||||
-->
|
||||
|
||||
|
||||
<!-- ========================================================== -->
|
||||
<!-- Context Parameters -->
|
||||
<!-- ========================================================== -->
|
||||
|
||||
<context-param>
|
||||
<param-name>org.eclipse.jetty.servlet.Default.welcomeServlets</param-name>
|
||||
<param-value>exact</param-value>
|
||||
</context-param>
|
||||
|
||||
|
||||
<!-- ========================================================== -->
|
||||
<!-- Servlets -->
|
||||
<!-- ========================================================== -->
|
||||
|
||||
<servlet>
|
||||
<servlet-name>jsp</servlet-name>
|
||||
<servlet-class>org.eclipse.jetty.jsp.JettyJspServlet</servlet-class>
|
||||
<init-param>
|
||||
<param-name>compilerSourceVM</param-name>
|
||||
<param-value>1.8</param-value>
|
||||
</init-param>
|
||||
<init-param>
|
||||
<param-name>compilerTargetVM</param-name>
|
||||
<param-value>1.8</param-value>
|
||||
</init-param>
|
||||
</servlet>
|
||||
|
||||
<servlet>
|
||||
<servlet-name>plantumlservlet</servlet-name>
|
||||
<servlet-class>net.sourceforge.plantuml.servlet.PlantUmlServlet</servlet-class>
|
||||
<load-on-startup>0</load-on-startup>
|
||||
</servlet>
|
||||
<servlet-mapping>
|
||||
<servlet-name>plantumlservlet</servlet-name>
|
||||
<url-pattern>/welcome</url-pattern>
|
||||
</servlet-mapping>
|
||||
<servlet-mapping>
|
||||
<servlet-name>plantumlservlet</servlet-name>
|
||||
<url-pattern>/uml/*</url-pattern>
|
||||
</servlet-mapping>
|
||||
<servlet-mapping>
|
||||
<servlet-name>plantumlservlet</servlet-name>
|
||||
<url-pattern>/form</url-pattern>
|
||||
</servlet-mapping>
|
||||
<servlet-mapping>
|
||||
<servlet-name>plantumlservlet</servlet-name>
|
||||
<url-pattern>/start/*</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<servlet>
|
||||
<servlet-name>imgservlet</servlet-name>
|
||||
<servlet-class>net.sourceforge.plantuml.servlet.ImgServlet</servlet-class>
|
||||
</servlet>
|
||||
<servlet-mapping>
|
||||
<servlet-name>imgservlet</servlet-name>
|
||||
<url-pattern>/png/*</url-pattern>
|
||||
</servlet-mapping>
|
||||
<servlet-mapping>
|
||||
<servlet-name>imgservlet</servlet-name>
|
||||
<url-pattern>/img/*</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<servlet>
|
||||
<servlet-name>svgservlet</servlet-name>
|
||||
<servlet-class>net.sourceforge.plantuml.servlet.SvgServlet</servlet-class>
|
||||
</servlet>
|
||||
<servlet-mapping>
|
||||
<servlet-name>svgservlet</servlet-name>
|
||||
<url-pattern>/svg/*</url-pattern>
|
||||
</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-name>epsservlet</servlet-name>
|
||||
<servlet-class>net.sourceforge.plantuml.servlet.EpsServlet</servlet-class>
|
||||
</servlet>
|
||||
<servlet-mapping>
|
||||
<servlet-name>epsservlet</servlet-name>
|
||||
<url-pattern>/eps/*</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<servlet>
|
||||
<servlet-name>epstextservlet</servlet-name>
|
||||
<servlet-class>net.sourceforge.plantuml.servlet.EpsTextServlet</servlet-class>
|
||||
</servlet>
|
||||
<servlet-mapping>
|
||||
<servlet-name>epstextservlet</servlet-name>
|
||||
<url-pattern>/epstext/*</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<servlet>
|
||||
<servlet-name>base64servlet</servlet-name>
|
||||
<servlet-class>net.sourceforge.plantuml.servlet.Base64Servlet</servlet-class>
|
||||
</servlet>
|
||||
<servlet-mapping>
|
||||
<servlet-name>base64servlet</servlet-name>
|
||||
<url-pattern>/base64/*</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<servlet>
|
||||
<servlet-name>asciiservlet</servlet-name>
|
||||
<servlet-class>net.sourceforge.plantuml.servlet.AsciiServlet</servlet-class>
|
||||
</servlet>
|
||||
<servlet-mapping>
|
||||
<servlet-name>asciiservlet</servlet-name>
|
||||
<url-pattern>/txt/*</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<servlet>
|
||||
<servlet-name>proxyservlet</servlet-name>
|
||||
<servlet-class>net.sourceforge.plantuml.servlet.ProxyServlet</servlet-class>
|
||||
</servlet>
|
||||
<servlet-mapping>
|
||||
<servlet-name>proxyservlet</servlet-name>
|
||||
<url-pattern>/proxy</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<servlet>
|
||||
<servlet-name>oldproxyservlet</servlet-name>
|
||||
<servlet-class>net.sourceforge.plantuml.servlet.OldProxyServlet</servlet-class>
|
||||
</servlet>
|
||||
<servlet-mapping>
|
||||
<servlet-name>oldproxyservlet</servlet-name>
|
||||
<url-pattern>/proxy/*</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<servlet>
|
||||
<servlet-name>mapservlet</servlet-name>
|
||||
<servlet-class>net.sourceforge.plantuml.servlet.MapServlet</servlet-class>
|
||||
</servlet>
|
||||
<servlet-mapping>
|
||||
<servlet-name>mapservlet</servlet-name>
|
||||
<url-pattern>/map/*</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<servlet>
|
||||
<servlet-name>checkservlet</servlet-name>
|
||||
<servlet-class>net.sourceforge.plantuml.servlet.CheckSyntaxServlet</servlet-class>
|
||||
</servlet>
|
||||
<servlet-mapping>
|
||||
<servlet-name>checkservlet</servlet-name>
|
||||
<url-pattern>/check/*</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<servlet>
|
||||
<servlet-name>languageservlet</servlet-name>
|
||||
<servlet-class>net.sourceforge.plantuml.servlet.LanguageServlet</servlet-class>
|
||||
</servlet>
|
||||
<servlet-mapping>
|
||||
<servlet-name>languageservlet</servlet-name>
|
||||
<url-pattern>/language</url-pattern>
|
||||
</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-page>
|
||||
<exception-type>java.lang.Throwable</exception-type>
|
||||
<location>/error.jsp</location>
|
||||
</error-page>
|
||||
|
||||
<error-page>
|
||||
<error-code>500</error-code>
|
||||
<location>/error.jsp</location>
|
||||
</error-page>
|
||||
|
||||
|
||||
<!-- ========================================================== -->
|
||||
<!-- Welcome Files -->
|
||||
<!-- ========================================================== -->
|
||||
|
||||
<welcome-file-list>
|
||||
<welcome-file>welcome</welcome-file>
|
||||
</welcome-file-list>
|
||||
|
||||
</web-app>
|
||||
|
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);
|
||||
}
|