diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml new file mode 100644 index 0000000..e4835e2 --- /dev/null +++ b/.github/workflows/docker.yml @@ -0,0 +1,78 @@ +name: Docker + +on: + workflow_run: + workflows: + - Main + types: + - completed + +jobs: + build: + runs-on: ubuntu-latest + if: github.event.workflow_run.conclusion == 'success' + steps: + - uses: actions/checkout@v2 + with: + fetch-depth: 0 + + - name: Docker tomcat meta + id: docker_meta_tomcat + uses: crazy-max/ghaction-docker-meta@v3 + with: + flavor: | + latest=false + prefix= + suffix= + images: plantuml/plantuml-server + tags: | + type=semver,pattern=tomcat-{{raw}} + type=raw,value=tomcat + + - name: Docker jetty meta + id: docker_meta_jetty + uses: crazy-max/ghaction-docker-meta@v3 + with: + flavor: | + latest=true + prefix= + suffix= + images: plantuml/plantuml-server + tags: | + type=semver,pattern={{raw}} + type=semver,pattern=jetty-{{raw}} + type=raw,value=jetty + + - name: Set up QEMU + uses: docker/setup-qemu-action@v1 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v1 + + - name: Login to DockerHub + uses: docker/login-action@v1 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + + - name: Build & push tomcat + id: docker_build_tomcat + uses: docker/build-push-action@v2 + with: + context: . + file: ./Dockerfile.tomcat + platforms: linux/amd64 + push: true + tags: ${{ steps.docker_meta_tomcat.outputs.tags }} + labels: ${{ steps.docker_meta_tomcat.outputs.labels }} + + - name: Build & push jetty + id: docker_build_jetty + uses: docker/build-push-action@v2 + with: + context: . + file: ./Dockerfile.jetty + platforms: linux/amd64 + push: true + tags: ${{ steps.docker_meta_jetty.outputs.tags }} + labels: ${{ steps.docker_meta_jetty.outputs.labels }} diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 2638904..a2b91fa 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -6,7 +6,7 @@ on: - "v*" jobs: - build: + build-jdk11: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 @@ -15,87 +15,98 @@ jobs: - uses: actions/setup-java@v2 with: - distribution: "adopt" - java-version: "8" + distribution: "zulu" + java-version: 11 check-latest: true cache: "maven" - - name: build with maven - run: mvn --batch-mode --define java.net.useSystemProxies=true package - - name: get tag name id: version run: echo ::set-output name=VERSION::${GITHUB_REF#refs/*/} + - name: build with maven + run: mvn --batch-mode --define java.net.useSystemProxies=true package + - name: create renamed build run: cp target/plantuml.war target/plantuml-${{ steps.version.outputs.VERSION }}.war + - name: build with maven (including the apache-jsp artifact) + run: mvn --batch-mode --define java.net.useSystemProxies=true -Dapache-jsp.scope=compile package + + - name: create renamed build (including the apache-jsp artifact) + run: cp target/plantuml.war target/plantuml-jsp-${{ steps.version.outputs.VERSION }}.war + + - name: temporarily save generated war files + uses: actions/upload-artifact@v2 + with: + name: war-jre11 + path: target/plantuml*-${{ steps.version.outputs.VERSION }}.war + + build-jdk8: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + with: + fetch-depth: 0 + + - uses: actions/setup-java@v2 + with: + distribution: "zulu" + java-version: 8 + check-latest: true + cache: "maven" + + - name: get tag name + id: version + run: echo ::set-output name=VERSION::${GITHUB_REF#refs/*/} + + - name: Remove test code (not java 8 compatible) + run: rm -rf src/test + + - name: build with maven + run: mvn --batch-mode -f pom.jdk8.xml --define java.net.useSystemProxies=true package + + - name: create renamed build + run: cp target/plantuml.war target/plantuml-jre8-${{ steps.version.outputs.VERSION }}.war + + - name: build with maven (including the apache-jsp artifact) + run: mvn --batch-mode -f pom.jdk8.xml --define java.net.useSystemProxies=true -Dapache-jsp.scope=compile package + + - name: create renamed build (including the apache-jsp artifact) + 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 + with: + name: war-jre8 + path: target/plantuml*-${{ steps.version.outputs.VERSION }}.war + + publish-releases: + runs-on: ubuntu-latest + needs: + - build-jdk11 + - build-jdk8 + steps: + - name: retrieve generated war files (jre8) + uses: actions/download-artifact@v2 + with: + name: war-jre8 + path: artifacts + + - name: retrieve generated war files (jre11) + uses: actions/download-artifact@v2 + with: + name: war-jre11 + path: artifacts + + - name: display structure of downloaded files + run: ls -lah artifacts + - name: upload binaries to release uses: svenstaro/upload-release-action@v2 with: repo_token: ${{ secrets.GITHUB_TOKEN }} - file: target/plantuml-${{ steps.version.outputs.VERSION }}.war - asset_name: plantuml-${{ steps.version.outputs.VERSION }}.war + file: artifacts/plantuml*.war tag: ${{ github.ref }} overwrite: true - - - name: Docker tomcat meta - id: docker_meta_tomcat - uses: crazy-max/ghaction-docker-meta@v3 - with: - flavor: | - latest=false - prefix= - suffix= - images: plantuml/plantuml-server - tags: | - type=semver,pattern=tomcat-{{raw}} - type=raw,value=tomcat - - - name: Docker jetty meta - id: docker_meta_jetty - uses: crazy-max/ghaction-docker-meta@v3 - with: - flavor: | - latest=true - prefix= - suffix= - images: plantuml/plantuml-server - tags: | - type=semver,pattern={{raw}} - type=semver,pattern=jetty-{{raw}} - type=raw,value=jetty - - - name: Set up QEMU - uses: docker/setup-qemu-action@v1 - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v1 - - - name: Login to DockerHub - uses: docker/login-action@v1 - with: - username: ${{ secrets.DOCKERHUB_USERNAME }} - password: ${{ secrets.DOCKERHUB_TOKEN }} - - - name: Build & push tomcat - id: docker_build_tomcat - uses: docker/build-push-action@v2 - with: - context: . - file: ./Dockerfile.tomcat - platforms: linux/amd64 - push: true - tags: ${{ steps.docker_meta_tomcat.outputs.tags }} - labels: ${{ steps.docker_meta_tomcat.outputs.labels }} - - - name: Build & push jetty - id: docker_build_jetty - uses: docker/build-push-action@v2 - with: - context: . - file: ./Dockerfile.jetty - platforms: linux/amd64 - push: true - tags: ${{ steps.docker_meta_jetty.outputs.tags }} - labels: ${{ steps.docker_meta_jetty.outputs.labels }} + file_glob: true diff --git a/.github/workflows/pages.yml b/.github/workflows/pages.yml index 133d0c5..5967ffe 100644 --- a/.github/workflows/pages.yml +++ b/.github/workflows/pages.yml @@ -19,8 +19,8 @@ jobs: - uses: actions/setup-java@v2 with: - distribution: "adopt" - java-version: "8" + distribution: "zulu" + java-version: 11 check-latest: true cache: "maven" diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index b117f95..72d6f59 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -5,7 +5,7 @@ on: - pull_request jobs: - test-mvn-livecycle: + test-java-8-war-generation: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 @@ -14,65 +14,110 @@ jobs: - uses: actions/setup-java@v2 with: - distribution: "adopt" - java-version: "8" + distribution: "zulu" + java-version: 8 + check-latest: true + cache: "maven" + + - name: Remove test code (not java 8 compatible) + run: rm -rf src/test + + - name: Generate war file (including apache-jsp artifact) + run: mvn --batch-mode -f pom.jdk8.xml -D java.net.useSystemProxies=true -Dapache-jsp.scope=compile clean package + + - name: Generate war file + 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 + with: + name: war-jre8 + path: target/plantuml.war + retention-days: 1 + + test-java-8-war: + runs-on: ubuntu-latest + needs: test-java-8-war-generation + strategy: + matrix: + java-version: [ 11, 17 ] + steps: + - uses: actions/checkout@v2 + with: + fetch-depth: 0 + + - name: retrieve generated files (jre8) + uses: actions/download-artifact@v2 + with: + name: war-jre8 + path: artifacts + + - uses: actions/setup-java@v2 + with: + distribution: "zulu" + java-version: ${{ matrix.java-version }} + check-latest: true + cache: "maven" + + - name: Prepare jetty-runner tests + run: mvn --batch-mode clean package + + - name: Start jetty server over jetty-runner + run: java -jar target/dependency/jetty-runner.jar --config src/main/config/jetty.xml --path /plantuml artifacts/plantuml.war & + + - name: Wait 5 seconds (to let jetty-runner start the jetty server) + 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" + + test-mvn-livecycle: + runs-on: ubuntu-latest + strategy: + matrix: + java-version: [ 11, 17 ] + steps: + - uses: actions/checkout@v2 + with: + fetch-depth: 0 + + - uses: actions/setup-java@v2 + with: + distribution: "zulu" + java-version: ${{ matrix.java-version }} check-latest: true cache: "maven" - name: Lifecycle - Step 1/8 - mvn clean - run: mvn clean + run: mvn --batch-mode clean - name: Lifecycle - Step 2/8 - mvn validate - run: mvn validate + run: mvn --batch-mode validate - name: Lifecycle - Step 3/8 - mvn compile - run: mvn compile + run: mvn --batch-mode compile - name: Lifecycle - Step 4/8 - mvn test (with skipTests=true) - run: mvn test + run: mvn --batch-mode test - name: Lifecycle - Step 5/8 - mvn package - run: mvn package + run: mvn --batch-mode package - name: Lifecycle - Step 6/8 - mvn verify - run: mvn verify + run: mvn --batch-mode verify - name: Lifecycle - Step 7/8 - mvn install - run: mvn install + run: mvn --batch-mode install - name: Lifecycle - Step 8/8 - mvn site - run: mvn site - - # test-embedded: - # runs-on: ubuntu-latest - # needs: test-mvn-livecycle - # steps: - # - uses: actions/checkout@v2 - # with: - # fetch-depth: 0 - - # - uses: actions/setup-java@v2 - # with: - # distribution: "adopt" - # java-version: "8" - # check-latest: true - # cache: "maven" - - # - name: Prepare embedded tests - Step 1/3 - mvn clean - # run: mvn clean + run: mvn --batch-mode site - # - name: Prepare embedded tests - Step 2/3 - mvn compile - # run: mvn compile - - # - name: Prepare embedded tests - Step 3/3 - mvn test (with skipTests=true) - # run: mvn test - - # - name: Run tests against jetty embedded server - # run: mvn test -DskipTests=false - - test-jetty: + test-embedded: runs-on: ubuntu-latest needs: test-mvn-livecycle + strategy: + matrix: + java-version: [ 11, 17 ] steps: - uses: actions/checkout@v2 with: @@ -80,19 +125,94 @@ jobs: - uses: actions/setup-java@v2 with: - distribution: "adopt" - java-version: "8" + distribution: "zulu" + java-version: ${{ matrix.java-version }} check-latest: true cache: "maven" - - name: Prepare external tests - Step 1/3 - mvn clean - run: mvn clean - - - name: Prepare external tests - Step 2/3 - mvn compile - run: mvn compile + - name: Run tests against jetty embedded server + run: mvn --batch-mode clean test -DskipTests=false - - name: Prepare external tests - Step 3/3 - mvn test (with skipTests=true) - run: mvn test + test-mvn-jetty-run: + runs-on: ubuntu-latest + needs: test-mvn-livecycle + strategy: + matrix: + java-version: [ 11, 17 ] + steps: + - uses: actions/checkout@v2 + with: + fetch-depth: 0 + + - uses: actions/setup-java@v2 + with: + distribution: "zulu" + java-version: ${{ matrix.java-version }} + check-latest: true + cache: "maven" + + - name: Prepare "mvn jetty:run" tests + run: mvn --batch-mode clean test + + - name: Start jetty server over maven + run: mvn --batch-mode jetty:run & + + - name: Wait 10 seconds (to let maven start the jetty server) + run: sleep 10s + + - name: Run tests against "mvn jetty:run" server + run: mvn --batch-mode test -DskipTests=false -DargLine="-Dsystem.test.server=http://localhost:8080/plantuml" + + test-jetty-runner: + runs-on: ubuntu-latest + needs: test-mvn-livecycle + strategy: + matrix: + java-version: [ 11, 17 ] + steps: + - uses: actions/checkout@v2 + with: + fetch-depth: 0 + + - uses: actions/setup-java@v2 + with: + distribution: "zulu" + java-version: ${{ matrix.java-version }} + check-latest: true + cache: "maven" + + - name: Prepare jetty-runner tests + run: mvn --batch-mode clean package + + - name: Start jetty server over jetty-runner + run: java -jar target/dependency/jetty-runner.jar --config src/main/config/jetty.xml --path /plantuml target/plantuml.war & + + - name: Wait 5 seconds (to let jetty-runner start the jetty server) + 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" + + test-jetty: + runs-on: ubuntu-latest + needs: test-mvn-livecycle + strategy: + matrix: + java-version: [ 11, 17 ] + steps: + - uses: actions/checkout@v2 + with: + fetch-depth: 0 + + - uses: actions/setup-java@v2 + with: + distribution: "zulu" + java-version: ${{ matrix.java-version }} + check-latest: true + cache: "maven" + + - name: Prepare external tests + run: mvn --batch-mode clean test - name: Build the jetty docker stack run: | @@ -103,11 +223,14 @@ jobs: run: docker ps - name: run tests against jetty docker image - run: mvn test -DskipTests=false -DargLine="-Dsystem.test.server=http://localhost:8080/plantuml" + run: mvn --batch-mode test -DskipTests=false -DargLine="-Dsystem.test.server=http://localhost:8080/plantuml" test-tomcat: runs-on: ubuntu-latest needs: test-mvn-livecycle + strategy: + matrix: + java-version: [ 11, 17 ] steps: - uses: actions/checkout@v2 with: @@ -115,19 +238,13 @@ jobs: - uses: actions/setup-java@v2 with: - distribution: "adopt" - java-version: "8" + distribution: "zulu" + java-version: ${{ matrix.java-version }} check-latest: true cache: "maven" - - name: Prepare external tests - Step 1/3 - mvn clean - run: mvn clean - - - name: Prepare external tests - Step 2/3 - mvn compile - run: mvn compile - - - name: Prepare external tests - Step 3/3 - mvn test (with skipTests=true) - run: mvn test + - name: Prepare external tests + run: mvn --batch-mode clean test - name: Build the tomcat docker stack run: | @@ -138,4 +255,4 @@ jobs: run: docker ps - name: run tests against tomcat docker image - run: mvn test -DskipTests=false -DargLine="-Dsystem.test.server=http://localhost:8080/plantuml" + run: mvn --batch-mode test -DskipTests=false -DargLine="-Dsystem.test.server=http://localhost:8080/plantuml" diff --git a/.vscode/settings.json b/.vscode/settings.json index c8c01dd..a78440a 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -14,7 +14,9 @@ "servlets", "startditaa", "startuml", - "utxt" + "utxt", + "ghaction", + "buildx" ], "cSpell.allowCompoundWords": true } \ No newline at end of file diff --git a/Dockerfile.jetty b/Dockerfile.jetty index ef3f0d3..8c8d6a2 100644 --- a/Dockerfile.jetty +++ b/Dockerfile.jetty @@ -8,7 +8,12 @@ RUN mvn --batch-mode --define java.net.useSystemProxies=true package ######################################################################################## -FROM jetty:9.4-jre11-slim +FROM jetty:11.0.7-jre11-slim + +# 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 apt-get update && \ diff --git a/Dockerfile.tomcat b/Dockerfile.tomcat index fcfb6cd..61efec7 100644 --- a/Dockerfile.tomcat +++ b/Dockerfile.tomcat @@ -4,11 +4,11 @@ COPY pom.xml /app/ COPY src/main /app/src/main/ WORKDIR /app -RUN mvn --batch-mode --define java.net.useSystemProxies=true package +RUN mvn --batch-mode --define java.net.useSystemProxies=true -Dapache-jsp.scope=compile package ######################################################################################## -FROM tomcat:9.0-jdk11-openjdk-slim +FROM tomcat:10-jdk11-openjdk-slim RUN apt-get update && \ apt-get install -y --no-install-recommends \ diff --git a/README.md b/README.md index 32a8bb9..e914ae7 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ To know more about PlantUML, please visit https://plantuml.com. ## Requirements -- jre/jdk 1.6.0 or above +- jre/jdk 11 or above - apache maven 3.0.2 or above @@ -36,7 +36,7 @@ In this way the server is run on an embedded jetty server. You can specify the port at which it runs: ```sh -mvn jetty:run -Djetty.port=9999 +mvn jetty:run -Djetty.http.port=9999 ``` @@ -74,18 +74,27 @@ And run `docker-compose up`. This will start a modified version of the image usi You can apply some option to your PlantUML server with environment variable. -If you run the directly the jar, you can pass the option with `-D` flag +If you run the directly the jar: ```sh -java -D THE_ENV_VARIABLE=THE_ENV_VALUE -Djetty.contextpath=/ -jar target/dependency/jetty-runner.jar target/plantuml.war +# NOTE: jetty-runner is deprecated. +# build war file and jetty-runner +mvn package +# start directly +# java $JVM_ARGS -jar jetty-runner.jar $JETTY_ARGS +java -jar target/dependency/jetty-runner.jar --config src/main/config/jetty.xml --port 9999 --path /plantuml target/plantuml.war +# see help for more possible options +java -jar target/dependency/jetty-runner.jar --help ``` -or +Note: `--config src/main/config/jetty.xml` is only necessary if you need support for empty path segments in URLs (e.g. for the old proxy) + +Alternatively, start over maven and pass the option with `-D` flag ```sh -mvn jetty:run -D THE_ENV_VARIABLE=THE_ENV_VALUE -Djetty.port=9999 +mvn jetty:run -D THE_ENV_VARIABLE=THE_ENV_VALUE -Djetty.http.port=9999 ``` If you use docker, you can use the `-e` flag: ```sh -docker run -d -p 8080:8080 -e THE_ENV_VARIABLE=THE_ENV_VALUE plantuml/plantuml-server:jetty +docker run -d -p 9999:8080 -e THE_ENV_VARIABLE=THE_ENV_VALUE plantuml/plantuml-server:jetty ``` You can set all the following variables: @@ -115,7 +124,7 @@ So, you can use following command to create a self-contained docker image that w *Note: Generate the WAR (instructions further below) prior to running "docker build"* ```sh -docker image build -t plantuml-server:local . +docker image build -f Dockerfile.jetty -t plantuml-server:local . docker run -d -p 8080:8080 plantuml-server:local ``` The server is now listening to [http://localhost:8080](http://localhost:8080). @@ -126,9 +135,18 @@ You may specify the port in `-p` Docker command line argument. ## How to generate the war To build the war, just run: - ```sh mvn package ``` - at the root directory of the project to produce plantuml.war in the target/ directory. + +NOTE: If you want that the generated war includes the `apache-jsp` artifact run: +```sh +mvn package -Dapache-jsp.scope=compile +``` + +If you want to generate the war with java 8 as target just remove the src/test directory and use `pom.jdk8.xml`. +```sh +rm -rf src/test +mvn package -f pom.jdk8.xml [-Dapache-jsp.scope=compile] +``` diff --git a/pom.jdk8.xml b/pom.jdk8.xml new file mode 100644 index 0000000..5ad1790 --- /dev/null +++ b/pom.jdk8.xml @@ -0,0 +1,509 @@ + + + 4.0.0 + + org.sourceforge.plantuml + plantumlservlet + 1-SNAPSHOT + war + + PlantUML Servlet + https://plantuml.github.io/plantuml-server/index.html + + + 8 + ${java.version} + ${java.version} + UTF-8 + UTF-8 + + + true + + + test + + yyyyMMdd-HHmm + ${maven.build.timestamp} + + 1.5 + plantuml + + 8080 + /${wtp.contextName} + + + 1.2021.12 + + 11.0.7 + 5.63.0 + 1.7.32 + + + 1.2 + ${jetty.version} + ${jetty.version} + ${jetty.version} + 1.14 + + 1.0.7 + ${jlatexmath.version} + ${jlatexmath.version} + + ${slf4j.version} + ${slf4j.version} + + 4.13.2 + 2.53.0 + ${jetty.version} + + + + 3.1.0 + 3.2.0 + 3.2.0 + 3.8.1 + 2.8.1 + 2.22.2 + 3.3.2 + 2.5.2 + 2.8.2 + 3.9.1 + 3.1.2 + 3.1.2 + 9.0.1 + + + 2.10 + ${jetty.version} + ${jetty.version} + 1.5.0 + 3.3.1 + + + + + net.sourceforge.plantuml + plantuml + ${plantuml.version} + + + org.webjars.npm + codemirror + ${codemirror.version} + + + jakarta.servlet + jakarta.servlet-api + 5.0.0 + provided + + + org.eclipse.jetty + apache-jsp + ${apache-jsp.version} + ${apache-jsp.scope} + + + org.eclipse.jetty.toolchain + jetty-jakarta-servlet-api + + + org.eclipse.jetty.toolchain + jetty-schemas + + + + + org.eclipse.jetty + jetty-annotations + ${jetty-annotations.version} + provided + + + org.eclipse.jetty.toolchain + jetty-jakarta-servlet-api + + + + + + org.apache.xmlgraphics + batik-all + ${batik-all.version} + pom + + + + org.scilab.forge + jlatexmath + ${jlatexmath.version} + + + org.scilab.forge + jlatexmath-font-greek + ${jlatexmath-font-greek.version} + + + org.scilab.forge + jlatexmath-font-cyrillic + ${jlatexmath-font-cyrillic.version} + + + + org.slf4j + slf4j-log4j12 + ${slf4j-log4j12.version} + + + org.slf4j + slf4j-api + ${slf4j-api.version} + + + + junit + junit + ${junit.version} + test + + + net.sourceforge.htmlunit + htmlunit + ${htmlunit.version} + test + + + org.eclipse.jetty + jetty-server + ${jetty-server.version} + test + + + org.eclipse.jetty.toolchain + jetty-jakarta-servlet-api + + + + + + + plantuml + + + + + maven-clean-plugin + ${maven-clean-plugin.version} + + + maven-dependency-plugin + ${maven-dependency-plugin.version} + + + maven-resources-plugin + ${maven-resources-plugin.version} + + + maven-compiler-plugin + ${maven-compiler-plugin.version} + + + maven-surefire-plugin + ${maven-surefire-plugin.version} + + + maven-war-plugin + ${maven-war-plugin.version} + + + maven-install-plugin + ${maven-install-plugin.version} + + + maven-deploy-plugin + ${maven-deploy-plugin.version} + + + maven-site-plugin + ${maven-site-plugin.version} + + + maven-project-info-reports-plugin + ${maven-project-info-reports-plugin.version} + + + org.apache.maven.plugins + maven-checkstyle-plugin + ${maven-checkstyle-plugin.version} + + + com.puppycrawl.tools + checkstyle + ${checkstyle.version} + + + + ${basedir}/src/main/config/checkstyle.xml + false + true + true + + + + org.codehaus.mojo + versions-maven-plugin + ${versions-maven-plugin.version} + + ${project.build.directory}/outdated-dependencies.txt + file:///${basedir}/src/main/config/rules.xml + + + + + + + + maven-compiler-plugin + ${maven-compiler-plugin.version} + + ${maven.compiler.source} + ${maven.compiler.target} + + + + org.apache.maven.plugins + maven-surefire-plugin + ${maven-surefire-plugin.version} + + ${skipTests} + + + + org.apache.maven.plugins + maven-site-plugin + ${maven-site-plugin.version} + + + org.apache.maven.plugins + maven-checkstyle-plugin + ${maven-checkstyle-plugin.version} + + + + validate + + check + + + + + + org.codehaus.mojo + versions-maven-plugin + ${versions-maven-plugin.version} + + + validate + + display-property-updates + + + + + + org.basepom.maven + duplicate-finder-maven-plugin + ${duplicate-finder-maven-plugin.version} + + + verify + + check + + + + + + ^about\.html$ + ^license/LICENSE\.dom-software\.txt$ + ^org/apache/batik/apps/rasterizer/resources/rasterizer\.policy$ + + + + + org.apache.maven.plugins + maven-javadoc-plugin + ${maven-javadoc-plugin.version} + + private + true + ${java.version} + true + + + + maven-dependency-plugin + ${maven-dependency-plugin.version} + + + + + unpack-resources + generate-test-sources + + unpack + + + + + org.webjars.npm + codemirror + ${codemirror.version} + **/lib/*.js,**/lib/*.css + ${project.build.outputDirectory} + + + + + + package + + copy + + + + + org.eclipse.jetty + jetty-runner + ${jetty-runner.version} + jetty-runner.jar + + + + + + + + org.apache.maven.plugins + maven-eclipse-plugin + ${maven-eclipse-plugin.version} + + ${wtp.version} + ${wtp.contextName} + + + + org.eclipse.jetty + jetty-maven-plugin + ${jetty-maven-plugin.version} + + + ${basedir}/src/main/config/jetty.xml + 5 + + ${jetty.contextpath} + + + + + org.apache.maven.plugins + maven-war-plugin + ${maven-war-plugin.version} + + + + ${basedir}/src/main/webapp + + *.jspf + + true + + + + + + + + + + + org.apache.maven.plugins + maven-project-info-reports-plugin + ${maven-project-info-reports-plugin.version} + + + + index + dependencies + + + + + + org.codehaus.mojo + versions-maven-plugin + ${versions-maven-plugin.version} + + + + + + property-updates-report + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + ${maven-javadoc-plugin.version} + + + html + + javadoc + + + + + + org.apache.maven.plugins + maven-checkstyle-plugin + ${maven-checkstyle-plugin.version} + + + + checkstyle + checkstyle-aggregate + + + + + + + diff --git a/pom.xml b/pom.xml index 5b427ee..a73f0dc 100644 --- a/pom.xml +++ b/pom.xml @@ -15,7 +15,7 @@ https://plantuml.github.io/plantuml-server/index.html - 8 + 11 ${java.version} ${java.version} UTF-8 @@ -29,31 +29,53 @@ --> true + + test + yyyyMMdd-HHmm ${maven.build.timestamp} 1.5 plantuml - 8080 + 8080 /${wtp.contextName} 1.2021.12 - 8.0.4.v20111024 + + 11.0.7 5.63.0 + 1.7.32 1.2 - 2.5 + ${jetty.version} + ${jetty.version} + ${jetty.version} 1.14 1.0.7 ${jlatexmath.version} ${jlatexmath.version} + + ${slf4j.version} + ${slf4j.version} 4.13.2 2.53.0 + ${jetty.version} @@ -73,39 +95,42 @@ 2.10 - - 8.1.9.v20130131 + ${jetty.version} ${jetty.version} + 1.5.0 3.3.1 - + net.sourceforge.plantuml plantuml ${plantuml.version} - - javax.servlet - jstl - ${jstl.version} - org.webjars.npm codemirror ${codemirror.version} - javax.servlet - servlet-api - ${servlet-api.version} + org.eclipse.jetty + apache-jsp + ${apache-jsp.version} + ${apache-jsp.scope} + + + org.eclipse.jetty + jetty-annotations + ${jetty-annotations.version} provided + org.apache.xmlgraphics batik-all ${batik-all.version} - + pom + org.scilab.forge @@ -122,6 +147,17 @@ jlatexmath-font-cyrillic ${jlatexmath-font-cyrillic.version} + + + org.slf4j + slf4j-log4j12 + ${slf4j-log4j12.version} + + + org.slf4j + slf4j-api + ${slf4j-api.version} + junit @@ -136,15 +172,9 @@ test - org.eclipse.jetty.aggregate - jetty-all - ${jetty.version} - test - - - org.mortbay.jetty - jsp-2.1-glassfish - 2.1.v20100127 + org.eclipse.jetty + jetty-server + ${jetty-server.version} test @@ -273,6 +303,26 @@ + + org.basepom.maven + duplicate-finder-maven-plugin + ${duplicate-finder-maven-plugin.version} + + + verify + + check + + + + + + ^about\.html$ + ^license/LICENSE\.dom-software\.txt$ + ^org/apache/batik/apps/rasterizer/resources/rasterizer\.policy$ + + + org.apache.maven.plugins maven-javadoc-plugin @@ -285,36 +335,29 @@ - org.apache.maven.plugins - maven-eclipse-plugin - ${maven-eclipse-plugin.version} - - ${wtp.version} - ${wtp.contextName} - - - - org.mortbay.jetty - jetty-maven-plugin - ${jetty-maven-plugin.version} - - 5 - - ${jetty.contextpath} - - - - jetty.port - ${jetty.port} - - - - - - org.apache.maven.plugins maven-dependency-plugin ${maven-dependency-plugin.version} + + + + unpack-resources + generate-test-sources + + unpack + + + + + org.webjars.npm + codemirror + ${codemirror.version} + **/lib/*.js,**/lib/*.css + ${project.build.outputDirectory} + + + + package @@ -323,7 +366,7 @@ - org.mortbay.jetty + org.eclipse.jetty jetty-runner ${jetty-runner.version} jetty-runner.jar @@ -333,6 +376,32 @@ + + org.apache.maven.plugins + maven-eclipse-plugin + ${maven-eclipse-plugin.version} + + ${wtp.version} + ${wtp.contextName} + + + + org.eclipse.jetty + jetty-maven-plugin + ${jetty-maven-plugin.version} + + + ${basedir}/src/main/config/jetty.xml + 5 + + ${jetty.contextpath} + + + org.apache.maven.plugins maven-war-plugin @@ -340,7 +409,7 @@ - src/main/webapp + ${basedir}/src/main/webapp *.jspf diff --git a/src/main/config/jetty.xml b/src/main/config/jetty.xml new file mode 100644 index 0000000..8af0434 --- /dev/null +++ b/src/main/config/jetty.xml @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/java/net/sourceforge/plantuml/servlet/CheckSyntaxServlet.java b/src/main/java/net/sourceforge/plantuml/servlet/CheckSyntaxServlet.java index 7f17c98..abcfc44 100644 --- a/src/main/java/net/sourceforge/plantuml/servlet/CheckSyntaxServlet.java +++ b/src/main/java/net/sourceforge/plantuml/servlet/CheckSyntaxServlet.java @@ -26,10 +26,11 @@ package net.sourceforge.plantuml.servlet; import java.io.IOException; import javax.imageio.IIOException; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; + +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.servlet.utility.UmlExtractor; diff --git a/src/main/java/net/sourceforge/plantuml/servlet/DiagramResponse.java b/src/main/java/net/sourceforge/plantuml/servlet/DiagramResponse.java index d969464..955c1c5 100644 --- a/src/main/java/net/sourceforge/plantuml/servlet/DiagramResponse.java +++ b/src/main/java/net/sourceforge/plantuml/servlet/DiagramResponse.java @@ -23,30 +23,30 @@ */ package net.sourceforge.plantuml.servlet; +import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.PrintWriter; -import java.io.ByteArrayOutputStream; import java.util.Collections; import java.util.HashMap; import java.util.Map; -import javax.servlet.http.HttpServletResponse; -import javax.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; import net.sourceforge.plantuml.BlockUml; +import net.sourceforge.plantuml.ErrorUml; import net.sourceforge.plantuml.FileFormat; import net.sourceforge.plantuml.FileFormatOption; -import net.sourceforge.plantuml.OptionFlags; 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.core.DiagramDescription; import net.sourceforge.plantuml.core.Diagram; +import net.sourceforge.plantuml.core.DiagramDescription; import net.sourceforge.plantuml.core.ImageData; -import net.sourceforge.plantuml.version.Version; import net.sourceforge.plantuml.error.PSystemError; -import net.sourceforge.plantuml.ErrorUml; +import net.sourceforge.plantuml.version.Version; /** * Delegates the diagram generation from the UML source and the filling of the HTTP response with the diagram in the diff --git a/src/main/java/net/sourceforge/plantuml/servlet/LanguageServlet.java b/src/main/java/net/sourceforge/plantuml/servlet/LanguageServlet.java index 1080f87..a0c8836 100644 --- a/src/main/java/net/sourceforge/plantuml/servlet/LanguageServlet.java +++ b/src/main/java/net/sourceforge/plantuml/servlet/LanguageServlet.java @@ -23,15 +23,16 @@ */ package net.sourceforge.plantuml.servlet; -import net.sourceforge.plantuml.syntax.LanguageDescriptor; - -import javax.servlet.ServletException; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.PrintStream; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServlet; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +import net.sourceforge.plantuml.syntax.LanguageDescriptor; + /** * Servlet used to inspect the language keywords of the running PlantUML server. * Same as {@code java -jar plantuml.jar -language} diff --git a/src/main/java/net/sourceforge/plantuml/servlet/MapServlet.java b/src/main/java/net/sourceforge/plantuml/servlet/MapServlet.java index 5097007..d647495 100644 --- a/src/main/java/net/sourceforge/plantuml/servlet/MapServlet.java +++ b/src/main/java/net/sourceforge/plantuml/servlet/MapServlet.java @@ -26,10 +26,11 @@ package net.sourceforge.plantuml.servlet; import java.io.IOException; import javax.imageio.IIOException; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; + +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.servlet.utility.UmlExtractor; diff --git a/src/main/java/net/sourceforge/plantuml/servlet/OldProxyServlet.java b/src/main/java/net/sourceforge/plantuml/servlet/OldProxyServlet.java index be11ad2..d3af50a 100644 --- a/src/main/java/net/sourceforge/plantuml/servlet/OldProxyServlet.java +++ b/src/main/java/net/sourceforge/plantuml/servlet/OldProxyServlet.java @@ -31,10 +31,10 @@ import java.net.URL; import java.util.regex.Matcher; import java.util.regex.Pattern; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; +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.FileFormatOption; diff --git a/src/main/java/net/sourceforge/plantuml/servlet/PlantUmlServlet.java b/src/main/java/net/sourceforge/plantuml/servlet/PlantUmlServlet.java index 5dde845..a4206fb 100644 --- a/src/main/java/net/sourceforge/plantuml/servlet/PlantUmlServlet.java +++ b/src/main/java/net/sourceforge/plantuml/servlet/PlantUmlServlet.java @@ -31,17 +31,20 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.net.ssl.HttpsURLConnection; -import javax.servlet.RequestDispatcher; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; + +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.png.MetadataTag; +import net.sourceforge.plantuml.servlet.utility.Configuration; +import net.sourceforge.plantuml.servlet.utility.UmlExtractor; /** * Original idea from Achim Abeling for Confluence macro. @@ -81,62 +84,36 @@ public class PlantUmlServlet extends HttpServlet { @Override public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { request.setCharacterEncoding("UTF-8"); - String text = request.getParameter("text"); - String metadata = request.getParameter("metadata"); - if (metadata != null) { - InputStream img = null; - try { - img = getImage(new URL(metadata)); - MetadataTag metadataTag = new MetadataTag(img, "plantuml"); - String data = metadataTag.getData(); - if (data != null) { - text = data; - } - } finally { - if (img != null) { - img.close(); - } - } - } - try { - text = getTextFromUrl(request, text); - } catch (Exception e) { - e.printStackTrace(); - } + // textual diagram source + final String text = getText(request).trim(); // no Text form has been submitted - if (text == null || text.trim().isEmpty()) { + if (text.isEmpty()) { redirectNow(request, response, DEFAULT_ENCODED_TEXT); return; } - final String encoded = getTranscoder().encode(text); - request.setAttribute("decoded", text); - request.setAttribute("encoded", encoded); - - // check if an image map is necessary - if (text != null && PlantumlUtils.hasCMapData(text)) { - request.setAttribute("mapneeded", Boolean.TRUE); - } - // forward to index.jsp + prepareRequestForDispatch(request, text); final RequestDispatcher dispatcher = request.getRequestDispatcher("/index.jsp"); dispatcher.forward(request, response); } @Override - protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, - IOException { + protected void doPost( + HttpServletRequest request, + HttpServletResponse response + ) throws ServletException, IOException { request.setCharacterEncoding("UTF-8"); - String text = request.getParameter("text"); - String encoded = DEFAULT_ENCODED_TEXT; - + // encoded diagram source + String encoded; try { - text = getTextFromUrl(request, text); + String text = getText(request).trim(); encoded = getTranscoder().encode(text); } catch (Exception e) { + encoded = DEFAULT_ENCODED_TEXT; e.printStackTrace(); } @@ -144,16 +121,59 @@ public class PlantUmlServlet extends HttpServlet { } /** - * Get textual diagram source from URL. + * Get textual diagram. + * Search for textual diagram in following order: + * 1. URL {@link PlantUmlServlet.getTextFromUrl} + * 2. metadata + * 3. request parameter "text" * - * @param request http request which contains the source URL - * @param text fallback textual diagram source + * @param request http request * - * @return if successful textual diagram source from URL; otherwise fallback {@code text} + * @return if successful textual diagram source; otherwise empty string * * @throws IOException if an input or output exception occurred */ - private String getTextFromUrl(HttpServletRequest request, String text) throws IOException { + private String getText(final HttpServletRequest request) throws IOException { + String text; + // 1. URL + try { + text = getTextFromUrl(request); + if (text != null && !text.isEmpty()) { + return text; + } + } catch (Exception e) { + e.printStackTrace(); + } + // 2. metadata + String metadata = request.getParameter("metadata"); + if (metadata != null) { + try (InputStream img = getImage(new URL(metadata))) { + MetadataTag metadataTag = new MetadataTag(img, "plantuml"); + String data = metadataTag.getData(); + if (data != null) { + return data; + } + } + } + // 3. request parameter text + text = request.getParameter("text"); + if (text != null && !text.isEmpty()) { + return text; + } + // nothing found + return ""; + } + + /** + * Get textual diagram source from URL. + * + * @param request http request which contains the source URL + * + * @return if successful textual diagram source from URL; otherwise empty string + * + * @throws IOException if an input or output exception occurred + */ + private String getTextFromUrl(HttpServletRequest request) throws IOException { final Matcher recoverUml = RECOVER_UML_PATTERN.matcher( request.getRequestURI().substring(request.getContextPath().length()) ); @@ -171,8 +191,75 @@ public class PlantUmlServlet extends HttpServlet { } return getTranscoder().decode(url); } - // fallback - return text; + // nothing found + return ""; + } + + /** + * Prepare request for dispatch and get request dispatcher. + * + * @param request http request which will be further prepared for dispatch + * @param text textual diagram source + * + * @throws IOException if an input or output exception occurred + */ + private void prepareRequestForDispatch(HttpServletRequest request, String text) throws IOException { + // diagram sources + final String encoded = getTranscoder().encode(text); + request.setAttribute("decoded", text); + request.setAttribute("encoded", encoded); + // 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/" + encoded); + request.setAttribute("svgurl", hostpath + "/svg/" + encoded); + request.setAttribute("txturl", hostpath + "/txt/" + encoded); + request.setAttribute("mapurl", hostpath + "/map/" + encoded); + // map for diagram source if necessary + final boolean hasMap = PlantumlUtils.hasCMapData(text); + request.setAttribute("hasMap", hasMap); + String map = ""; + if (hasMap) { + try { + map = UmlExtractor.extractMap(text); + } catch (Exception e) { + e.printStackTrace(); + } + } + 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(); } /** diff --git a/src/main/java/net/sourceforge/plantuml/servlet/ProxyServlet.java b/src/main/java/net/sourceforge/plantuml/servlet/ProxyServlet.java index 7981dc0..28e35ef 100644 --- a/src/main/java/net/sourceforge/plantuml/servlet/ProxyServlet.java +++ b/src/main/java/net/sourceforge/plantuml/servlet/ProxyServlet.java @@ -29,11 +29,17 @@ 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 javax.servlet.ServletException; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; +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; @@ -42,13 +48,6 @@ import net.sourceforge.plantuml.SourceStringReader; import net.sourceforge.plantuml.core.Diagram; import net.sourceforge.plantuml.core.UmlSource; -import java.security.cert.Certificate; -import java.util.List; - -import javax.imageio.IIOException; -import javax.net.ssl.HttpsURLConnection; -import javax.net.ssl.SSLPeerUnverifiedException; - /** * Proxy servlet of the webapp. * This servlet retrieves the diagram source of a web resource (web html page) diff --git a/src/main/java/net/sourceforge/plantuml/servlet/UmlDiagramService.java b/src/main/java/net/sourceforge/plantuml/servlet/UmlDiagramService.java index dc46b10..d75179a 100644 --- a/src/main/java/net/sourceforge/plantuml/servlet/UmlDiagramService.java +++ b/src/main/java/net/sourceforge/plantuml/servlet/UmlDiagramService.java @@ -23,20 +23,21 @@ */ package net.sourceforge.plantuml.servlet; -import net.sourceforge.plantuml.FileFormat; -import net.sourceforge.plantuml.OptionFlags; -import net.sourceforge.plantuml.servlet.utility.UmlExtractor; - -import javax.imageio.IIOException; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; import java.io.BufferedReader; import java.io.IOException; import java.util.regex.Matcher; import java.util.regex.Pattern; +import javax.imageio.IIOException; + +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.OptionFlags; +import net.sourceforge.plantuml.servlet.utility.UmlExtractor; + /** * Common service servlet to produce diagram from compressed UML source contained in the end part of the requested URI. */ diff --git a/src/main/java/net/sourceforge/plantuml/servlet/Welcome.java b/src/main/java/net/sourceforge/plantuml/servlet/Welcome.java deleted file mode 100644 index ef9da69..0000000 --- a/src/main/java/net/sourceforge/plantuml/servlet/Welcome.java +++ /dev/null @@ -1,53 +0,0 @@ -/* ======================================================================== - * 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.IOException; - -import javax.servlet.RequestDispatcher; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -/** - * Welcome servlet of the webapp. - * Displays the sample Bob and Alice sequence diagram. - */ -@SuppressWarnings("SERIAL") -public class Welcome extends HttpServlet { - - @Override - public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { - - // set the sample - request.setAttribute("decoded", "Bob -> Alice : hello"); - request.setAttribute("encoded", "SyfFKj2rKt3CoKnELR1Io4ZDoSa70000"); - - // forward to index.jsp - RequestDispatcher dispatcher = request.getRequestDispatcher("/index.jsp"); - dispatcher.forward(request, response); - } - -} diff --git a/src/main/java/net/sourceforge/plantuml/servlet/utility/Configuration.java b/src/main/java/net/sourceforge/plantuml/servlet/utility/Configuration.java index 2489a06..2af6c3b 100644 --- a/src/main/java/net/sourceforge/plantuml/servlet/utility/Configuration.java +++ b/src/main/java/net/sourceforge/plantuml/servlet/utility/Configuration.java @@ -85,10 +85,10 @@ public final class Configuration { * @return true if the value is "on" */ public static boolean get(final String key) { - if (instance.config.getProperty(key) == null) { + if (get().getProperty(key) == null) { return false; } - return instance.config.getProperty(key).startsWith("on"); + return get().getProperty(key).startsWith("on"); } } diff --git a/src/main/java/net/sourceforge/plantuml/servlet/utility/UmlExtractor.java b/src/main/java/net/sourceforge/plantuml/servlet/utility/UmlExtractor.java index 49c30dd..4287fa3 100644 --- a/src/main/java/net/sourceforge/plantuml/servlet/utility/UmlExtractor.java +++ b/src/main/java/net/sourceforge/plantuml/servlet/utility/UmlExtractor.java @@ -27,9 +27,14 @@ import java.io.IOException; import java.io.UnsupportedEncodingException; 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; +import net.sourceforge.plantuml.core.Diagram; +import net.sourceforge.plantuml.core.ImageData; /** * Utility class to extract the UML source from the compressed UML source contained in the end part @@ -84,4 +89,36 @@ public abstract class UmlExtractor { return uml; } + /** + * Get image map from uml. + * + * @param uml textual diagram source + * + * @return image map of the diagram in HTML format if the image has some position information; otherwise `null` + * + * @throws IOException if an input or output exception occurred + */ + public static String extractMap(final String uml) throws IOException { + return extractMap(uml, FileFormat.PNG); + } + + /** + * Get image map from uml. + * + * @param uml textual diagram source + * @param fileFormat underlying file format of uml image + * + * @return image map of the diagram in HTML format if the image has some position information; otherwise `null` + * + * @throws IOException if an input or output exception occurred + */ + public static String extractMap(final String uml, final FileFormat fileFormat) throws IOException { + Diagram diagram = new SourceStringReader(uml).getBlocks().get(0).getDiagram(); + ImageData map = diagram.exportDiagram(new NullOutputStream(), 0, new FileFormatOption(fileFormat, false)); + if (map.containsCMapData()) { + return map.getCMapData("plantuml"); + } + return null; + } + } diff --git a/src/main/resources/log4j.properties b/src/main/resources/log4j.properties new file mode 100644 index 0000000..2612f44 --- /dev/null +++ b/src/main/resources/log4j.properties @@ -0,0 +1,6 @@ +# Logger configuration file +# +log4j.rootCategory=INFO, stdout +log4j.appender.stdout=org.apache.log4j.ConsoleAppender +log4j.appender.stdout.layout=org.apache.log4j.PatternLayout +log4j.appender.stdout.layout.ConversionPattern=%d{yy-MM-dd HH:mm:ss:SSS} %5p %t %c{2}:%L - %m%n diff --git a/src/main/webapp/WEB-INF/web.xml b/src/main/webapp/WEB-INF/web.xml index 00d917c..ae4992e 100644 --- a/src/main/webapp/WEB-INF/web.xml +++ b/src/main/webapp/WEB-INF/web.xml @@ -1,150 +1,219 @@ - - plantuml - - org.eclipse.jetty.servlet.Default.welcomeServlets - exact - - - jsp - org.apache.jasper.servlet.JspServlet - - compilerSourceVM - 1.7 - - - compilerTargetVM - 1.7 - - - - plantumlservlet - net.sourceforge.plantuml.servlet.PlantUmlServlet - - - welcome - net.sourceforge.plantuml.servlet.Welcome - - - imgservlet - net.sourceforge.plantuml.servlet.ImgServlet - - - svgservlet - net.sourceforge.plantuml.servlet.SvgServlet - - - epsservlet - net.sourceforge.plantuml.servlet.EpsServlet - - - epstextservlet - net.sourceforge.plantuml.servlet.EpsTextServlet - - - base64servlet - net.sourceforge.plantuml.servlet.Base64Servlet - - - asciiservlet - net.sourceforge.plantuml.servlet.AsciiServlet - - - proxyservlet - net.sourceforge.plantuml.servlet.ProxyServlet - - - oldproxyservlet - net.sourceforge.plantuml.servlet.OldProxyServlet - - - mapservlet - net.sourceforge.plantuml.servlet.MapServlet - - - checkservlet - net.sourceforge.plantuml.servlet.CheckSyntaxServlet - - - languageservlet - net.sourceforge.plantuml.servlet.LanguageServlet - - - - plantumlservlet - /welcome - - - plantumlservlet - /uml/* - - - plantumlservlet - /form - - - imgservlet - /png/* - - - imgservlet - /img/* - - - svgservlet - /svg/* - - - epsservlet - /eps/* - - - epstextservlet - /epstext/* - - - base64servlet - /base64/* - - - asciiservlet - /txt/* - - - checkservlet - /check/* - - - mapservlet - /map/* - - - plantumlservlet - /start/* - - - oldproxyservlet - /proxy/* - - - proxyservlet - /proxy - - - languageservlet - /language - - - java.lang.Throwable - /error.jsp - - - 500 - /error.jsp - - - welcome - + + + + + + + + PlantUML + PlantUML Online Server + + + + + + + 120 + + + + + + + + + + + + + + + + + + + org.eclipse.jetty.servlet.Default.welcomeServlets + exact + + + + + + + + + jsp + org.eclipse.jetty.jsp.JettyJspServlet + + compilerSourceVM + 1.7 + + + compilerTargetVM + 1.7 + + + + + plantumlservlet + net.sourceforge.plantuml.servlet.PlantUmlServlet + + + plantumlservlet + /welcome + + + plantumlservlet + /uml/* + + + plantumlservlet + /form + + + plantumlservlet + /start/* + + + + imgservlet + net.sourceforge.plantuml.servlet.ImgServlet + + + imgservlet + /png/* + + + imgservlet + /img/* + + + + svgservlet + net.sourceforge.plantuml.servlet.SvgServlet + + + svgservlet + /svg/* + + + + epsservlet + net.sourceforge.plantuml.servlet.EpsServlet + + + epsservlet + /eps/* + + + + epstextservlet + net.sourceforge.plantuml.servlet.EpsTextServlet + + + epstextservlet + /epstext/* + + + + base64servlet + net.sourceforge.plantuml.servlet.Base64Servlet + + + base64servlet + /base64/* + + + + asciiservlet + net.sourceforge.plantuml.servlet.AsciiServlet + + + asciiservlet + /txt/* + + + + proxyservlet + net.sourceforge.plantuml.servlet.ProxyServlet + + + proxyservlet + /proxy + + + + oldproxyservlet + net.sourceforge.plantuml.servlet.OldProxyServlet + + + oldproxyservlet + /proxy/* + + + + mapservlet + net.sourceforge.plantuml.servlet.MapServlet + + + mapservlet + /map/* + + + + checkservlet + net.sourceforge.plantuml.servlet.CheckSyntaxServlet + + + checkservlet + /check/* + + + + languageservlet + net.sourceforge.plantuml.servlet.LanguageServlet + + + languageservlet + /language + + + + + + + + + java.lang.Throwable + /error.jsp + + + + 500 + /error.jsp + + + + + + + + + welcome + + diff --git a/src/main/webapp/error.jsp b/src/main/webapp/error.jsp index 36691d8..247ebbd 100644 --- a/src/main/webapp/error.jsp +++ b/src/main/webapp/error.jsp @@ -1,12 +1,21 @@ <%@ page isErrorPage="true" contentType="text/html; charset=utf-8" pageEncoding="utf-8" session="false" %> - - - - - - +<% + String contextroot = request.getContextPath(); + String port = ""; + if ( + (request.getScheme() == "http" && request.getServerPort() != 80) + || + (request.getScheme() == "https" && request.getServerPort() != 443) + ) { + port = ":" + request.getServerPort(); + } + String scheme = request.getScheme(); + if (request.getHeader("x-forwarded-proto") != null && request.getHeader("x-forwarded-proto") != "") { + scheme = request.getHeader("x-forwarded-proto"); + } + String hostpath = scheme + "://" + request.getServerName() + port + contextroot; +%> @@ -15,23 +24,23 @@ - - - + + + PlantUMLServer Error -

-Sorry, but things didn't work out as planned. -

-
- -
    -
  • <%=now.toString() %>
  • -
  • Request that failed: <%=pageContext.getErrorData().getRequestURI() %>
  • -
  • Status code: <%=pageContext.getErrorData().getStatusCode() %>
  • -
  • Exception: <%=pageContext.getErrorData().getThrowable() %>
  • -
-
+

+ Sorry, but things didn't work out as planned. +

+
+ +
    +
  • <%= now.toString() %>
  • +
  • Request that failed: <%= pageContext.getErrorData().getRequestURI() %>
  • +
  • Status code: <%= pageContext.getErrorData().getStatusCode() %>
  • +
  • Exception: <%= pageContext.getErrorData().getThrowable() %>
  • +
+
- \ No newline at end of file + diff --git a/src/main/webapp/footer.jspf b/src/main/webapp/footer.jspf index eea5155..509d089 100644 --- a/src/main/webapp/footer.jspf +++ b/src/main/webapp/footer.jspf @@ -1,5 +1,4 @@ - \ No newline at end of file +

PlantUML Server Version <%= net.sourceforge.plantuml.version.Version.version() %> +

+ diff --git a/src/main/webapp/index.jsp b/src/main/webapp/index.jsp index 8234913..25d16db 100644 --- a/src/main/webapp/index.jsp +++ b/src/main/webapp/index.jsp @@ -1,22 +1,24 @@ <%@ page info="index" contentType="text/html; charset=utf-8" pageEncoding="utf-8" session="false" %> -<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> - - - - - - - - - - - - - - - +<% + // diagram sources + String decoded = request.getAttribute("decoded").toString(); + String encoded = request.getAttribute("encoded").toString(); + // properties + boolean showSocialButtons = (boolean)request.getAttribute("showSocialButtons"); + boolean showGithubRibbon = (boolean)request.getAttribute("showGithubRibbon"); + // URL base + String hostpath = request.getAttribute("hostpath").toString(); + // image URLs + boolean hasImg = (boolean)request.getAttribute("hasImg"); + String imgurl = request.getAttribute("imgurl").toString(); + String svgurl = request.getAttribute("svgurl").toString(); + String txturl = request.getAttribute("txturl").toString(); + String mapurl = request.getAttribute("mapurl").toString(); + // map for diagram source if necessary + boolean hasMap = (boolean)request.getAttribute("hasMap"); + String map = request.getAttribute("map").toString(); +%> @@ -25,73 +27,67 @@ - - - - - + + + + + PlantUMLServer - -
- <%-- CONTENT --%> -
-

- - -

-
-
-

You can enter here a previously generated URL:

-
-

- -
- -

-
- + +
+ <%-- CONTENT --%> +
+

+ + +

+

- View as SVG  - View as ASCII Art  - - View Map Data - - - <%@ include file="resource/socialbuttons2.jspf" %> - -

- - - PlantUML diagram - - - PlantUML diagram - - -

- -
-<%-- FOOTER --%> -<%@ include file="footer.jspf" %> +

You can enter here a previously generated URL:

+
+

+ +
+ +

+
+ <% if (hasImg) { %> +
+ View as SVG  + View as ASCII Art  + <% if (hasMap) { %> + View Map Data + <% } %> + <% if (showSocialButtons) { %> + <%@ include file="resource/socialbuttons2.jspf" %> + <% } %> +

+ PlantUML diagram + <%= map %> +

+ <% } %> +
+ <%-- FOOTER --%> + <%@ include file="footer.jspf" %> diff --git a/src/test/java/net/sourceforge/plantuml/servlet/TestForm.java b/src/test/java/net/sourceforge/plantuml/servlet/TestForm.java index 7a1a1e5..42cf7a6 100644 --- a/src/test/java/net/sourceforge/plantuml/servlet/TestForm.java +++ b/src/test/java/net/sourceforge/plantuml/servlet/TestForm.java @@ -183,10 +183,10 @@ public class TestForm extends WebappTestCase { HtmlImage img = page.getFirstByXPath("//img[contains(@alt, 'PlantUML diagram')]"); assertNotEquals(0, img.getImageReader().getHeight(0)); // 131 assertNotEquals(0, img.getImageReader().getWidth(0)); // 231 - // TODO: Ensure the image map is present - //DomElement map = page.getElementById("plantuml_map"); - //assertNotNull(map); - //assertEquals(1, map.getChildElementCount()); + // Ensure the image map is present + DomElement map = page.getElementById("plantuml_map"); + assertNotNull(map); + assertEquals(1, map.getChildElementCount()); } } diff --git a/src/test/java/net/sourceforge/plantuml/servlet/WebappTestCase.java b/src/test/java/net/sourceforge/plantuml/servlet/WebappTestCase.java index 6ff12c0..6201650 100644 --- a/src/test/java/net/sourceforge/plantuml/servlet/WebappTestCase.java +++ b/src/test/java/net/sourceforge/plantuml/servlet/WebappTestCase.java @@ -8,6 +8,9 @@ import java.io.InputStreamReader; import java.net.URL; import java.net.URLConnection; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import junit.framework.TestCase; import net.sourceforge.plantuml.servlet.server.EmbeddedJettyServer; import net.sourceforge.plantuml.servlet.server.ExternalServer; @@ -16,6 +19,8 @@ import net.sourceforge.plantuml.servlet.server.ServerUtils; public abstract class WebappTestCase extends TestCase { + protected final Logger logger; + private final ServerUtils serverUtils; public WebappTestCase() { @@ -24,24 +29,26 @@ public abstract class WebappTestCase extends TestCase { public WebappTestCase(String name) { super(name); + logger = LoggerFactory.getLogger(this.getClass()); String uri = System.getProperty("system.test.server", ""); //uri = "http://localhost:8080/plantuml"; if (!uri.isEmpty()) { // mvn test -DskipTests=false -DargLine="-Dsystem.test.server=http://localhost:8080/plantuml" - System.out.println("Test against external server: " + uri); + logger.info("Test against external server: " + uri); serverUtils = new ExternalServer(uri); return; } // mvn test -DskipTests=false - System.out.println("Test against embedded jetty server."); + logger.info("Test against embedded jetty server."); serverUtils = new EmbeddedJettyServer(); } @Override public void setUp() throws Exception { serverUtils.startServer(); + logger.info(getServerUrl()); } @Override diff --git a/src/test/java/net/sourceforge/plantuml/servlet/server/EmbeddedJettyServer.java b/src/test/java/net/sourceforge/plantuml/servlet/server/EmbeddedJettyServer.java index 75b81de..19f8f8e 100644 --- a/src/test/java/net/sourceforge/plantuml/servlet/server/EmbeddedJettyServer.java +++ b/src/test/java/net/sourceforge/plantuml/servlet/server/EmbeddedJettyServer.java @@ -1,19 +1,51 @@ package net.sourceforge.plantuml.servlet.server; -import java.net.InetSocketAddress; +import java.util.EnumSet; -import org.eclipse.jetty.server.Connector; +import org.eclipse.jetty.http.UriCompliance; +import org.eclipse.jetty.http.UriCompliance.Violation; +import org.eclipse.jetty.server.HttpConnectionFactory; import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.server.ServerConnector; +import org.eclipse.jetty.server.handler.DefaultHandler; +import org.eclipse.jetty.server.handler.HandlerList; import org.eclipse.jetty.webapp.WebAppContext; - public class EmbeddedJettyServer implements ServerUtils { + private static final String contextPath = "/plantuml"; private Server server; public EmbeddedJettyServer() { - server = new Server(new InetSocketAddress("127.0.0.1", 0)); - server.addBean(new WebAppContext(server, "src/main/webapp", "/plantuml")); + server = new Server(); + + ServerConnector connector = new ServerConnector(server); + // Proxy and OldProxy need empty path segments support in URIs + // Hence: allow AMBIGUOUS_EMPTY_SEGMENT + UriCompliance uriCompliance = UriCompliance.from(EnumSet.of(Violation.AMBIGUOUS_EMPTY_SEGMENT)); + connector.getConnectionFactory(HttpConnectionFactory.class) + .getHttpConfiguration() + .setUriCompliance(uriCompliance); + server.addConnector(connector); + + // PlantUML server web application + WebAppContext context = new WebAppContext(server, "src/main/webapp", EmbeddedJettyServer.contextPath); + + // Add static webjars resource files + // The maven-dependency-plugin in the pom.xml provides these files. + WebAppContext res = new WebAppContext( + server, + "target/classes/META-INF/resources/webjars", + EmbeddedJettyServer.contextPath + "/webjars" + ); + + // Create server handler + HandlerList handlers = new HandlerList(); + handlers.addHandler(res); // provides: /plantuml/webjars + handlers.addHandler(context); // provides: /plantuml + handlers.addHandler(new DefaultHandler()); // provides: / + + server.setHandler(handlers); } public void startServer() throws Exception { @@ -25,8 +57,12 @@ public class EmbeddedJettyServer implements ServerUtils { } public String getServerUrl() { - Connector connector = server.getConnectors()[0]; - return String.format("http://%s:%d/plantuml", connector.getHost(), connector.getLocalPort()); + return String.format( + "%s://%s%s", + server.getURI().getScheme(), + server.getURI().getAuthority(), + EmbeddedJettyServer.contextPath + ); } }