From 95f4c9714e743b7e11ba5299fffe2057c608bd26 Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Tue, 1 Jun 2021 02:37:32 -0700 Subject: [PATCH] Implemented StatusCode bean. Closes #5 --- .github/workflows/gradle.yml | 10 ++ README.md | 76 +++++++-- build.gradle | 8 + .../thauvin/erik/httpstatus/StatusCode.java | 149 ++++++++++++++++++ .../erik/httpstatus/taglibs/ReasonTag.java | 2 - .../erik/httpstatus/StatusCodeTest.java | 76 +++++++++ 6 files changed, 306 insertions(+), 15 deletions(-) create mode 100644 src/main/java/net/thauvin/erik/httpstatus/StatusCode.java create mode 100644 src/test/java/net/thauvin/erik/httpstatus/StatusCodeTest.java diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml index eef517b..251e704 100644 --- a/.github/workflows/gradle.yml +++ b/.github/workflows/gradle.yml @@ -5,22 +5,28 @@ on: [push, pull_request, workflow_dispatch] jobs: build: runs-on: ubuntu-latest + env: GRADLE_OPTS: "-Dorg.gradle.jvmargs=-XX:MaxMetaspaceSize=512m" SONAR_JDK: "11" + strategy: matrix: java-version: [ 1.8, 11, 15 ] + steps: - uses: actions/checkout@v2 with: fetch-depth: 0 + - name: Set up JDK ${{ matrix.java-version }} uses: actions/setup-java@v1 with: java-version: ${{ matrix.java-version }} + - name: Grant execute permission for gradlew run: chmod +x gradlew + - name: Cache SonarCloud packages if: matrix.java-version == env.SONAR_JDK uses: actions/cache@v1 @@ -28,6 +34,7 @@ jobs: path: ~/.sonar/cache key: ${{ runner.os }}-sonar restore-keys: ${{ runner.os }}-sonar + - name: Cache Gradle packages uses: actions/cache@v2 with: @@ -37,14 +44,17 @@ jobs: key: ${{ runner.os }}-gradle-${{ matrix.java-version }}-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }} restore-keys: | ${{ runner.os }}-gradle-${{ matrix.java-version }}- + - name: Test with Gradle run: ./gradlew build check --stacktrace + - name: SonarCloud if: success() && matrix.java-version == env.SONAR_JDK env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} run: ./gradlew sonarqube + - name: Cleanup Gradle Cache run: | rm -f ~/.gradle/caches/modules-2/modules-2.lock diff --git a/README.md b/README.md index c19b75d..ee683a2 100644 --- a/README.md +++ b/README.md @@ -32,6 +32,25 @@ would display on a [501 status code](http://www.w3.org/Protocols/rfc2616/rfc2616 Not Implemented +## Usage with [Gradle](https://gradle.org/) or [Maven](http://maven.apache.org/) +Include the following in your `build.gradle` file: + +```gradle +dependencies { + implementation 'net.thauvin.erik.httpstatus:httpstatus:1.0.6' +} +``` + +or as a Maven artifact: + +```xml + + net.thauvin.erik.httpstatus + httpstatus + 1.0.6 + +``` + ## hs:cause The `` tag displays the cause of current HTTP status code, if any. A shorthand for: @@ -175,24 +194,55 @@ Status Code | Reason `598` | Network Read Timeout Error `599` | Network Connect Timeout Error -## Usage with [Gradle](https://gradle.org/) or [Maven](http://maven.apache.org/) -Include the following in your `build.gradle` file: +## StatusCode Bean -```gradle -dependencies { - implementation 'net.thauvin.erik.httpstatus:httpstatus:1.0.6' +The `StatusCode` bean can be used to check the class of the status code error. For example, using the JSTL: + +```jsp +<%@ taglib prefix="hs" uri="http://erik.thauvin.net/taglibs/httpstatus" %> +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> + + + + + + An error occurred on your side. () + + + An error occurred on our side. () + + +``` + +or in a Servlet: + +```java +import net.thauvin.erik.httpstatus.StatusCode; + +// --- + +final StatusCode statusCode = new StatusCode((Integer) request.getAttribute("javax.servlet.error.status_code")); +if (statusCode.isError()) { + if (statusCode.isServerError()) { + final String reason = statusCode.getReason(); + } else { + // ... + } } ``` -or as a Maven artifact: +The `StatusCode` bean methods are: -```xml - - net.thauvin.erik.httpstatus - httpstatus - 1.0.6 - -``` +Method | Description +----------------- | ------------------------------------------------------------------ +`getReason` | Returns the reason for the status code (eg: Internal Server Error) +'isClientError' | Checks if the status code is a client error. +`isError` | Checks if the status code is a server or client error. +`isInfo` | Checks if the status code is informational. +`isRedirect` | Checks if the status code is a redirect. +`isServerError' | Checks if the status code is a server error. +`isSuccess` | Checks if the status code is a success. (`OK`) +`isValid` | Checks if the status code is valid. ## Command Line Usage You can query the reason phrase for status codes as follows: diff --git a/build.gradle b/build.gradle index 0700f6c..4746236 100644 --- a/build.gradle +++ b/build.gradle @@ -103,6 +103,7 @@ test { spotbugs { toolVersion = versions.spotbugs excludeFilter = file("$projectDir/config/spotbugs/excludeFilter.xml") + } pmd { @@ -120,6 +121,13 @@ tasks.withType(Checkstyle) { } } +tasks.withType(SpotBugsTask) { + reports { + xml.enabled = false + html.enabled = true + } +} + publishing { publications { mavenJava(MavenPublication) { diff --git a/src/main/java/net/thauvin/erik/httpstatus/StatusCode.java b/src/main/java/net/thauvin/erik/httpstatus/StatusCode.java new file mode 100644 index 0000000..e6a4df7 --- /dev/null +++ b/src/main/java/net/thauvin/erik/httpstatus/StatusCode.java @@ -0,0 +1,149 @@ +/* + * StatusCode.java + * + * Copyright (c) 2015-2021, Erik C. Thauvin (erik@thauvin.net) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of this project nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package net.thauvin.erik.httpstatus; + +import java.io.Serializable; + +/** + * The StatusCode class implements methods to check the class of a HTTP status code. + * + * @author Erik C. Thauvin + */ +public class StatusCode implements Serializable { + private static final long serialVersionUID = 1L; + private int code; + + /** + * Creates a new statusCode object. + */ + public StatusCode() { + // Default construtor. + } + + /** + * Creates a new StatusCode object. + * + * @param code The status code. + */ + public StatusCode(final int code) { + this.code = code; + } + + /** + * Returns the status code. + */ + public int getCode() { + return code; + } + + /** + * Returns the reason for the status code. + * + * @return The reason, or null. + */ + public String getReason() { + return Reasons.getReasonPhrase(code); + } + + /** + * Checks if the status code is a client error. + * + * @return true if the status code is a client error, false otherwise. + */ + public boolean isClientError() { + return code >= 400 && code < 500; + } + + /** + * Checks if the status code is a client or server error. + * + * @return true if the status code is an error, false otherwise. + */ + public boolean isError() { + return code >= 400 && code < 600; + } + + /** + * Checks if the status code is informational. + * + * @return true if the status code is informational, false otherwise. + */ + public boolean isInfo() { + return code >= 100 && code < 200; + } + + /** + * Checks if the status code is a redirect. + * + * @return true if the status code is a redirect, false otherwise. + */ + public boolean isRedirect() { + return code >= 300 && code < 400; + } + + /** + * Checks if the status code is a server error. + * + * @return true if the status code is a server error, false otherwise. + */ + public boolean isServerError() { + return code >= 500 && code < 600; + } + + /** + * Checks if the status code is a (OK) success. + * + * @return true if the status code is a success, false otherwise. + */ + public boolean isSuccess() { + return code >= 200 && code < 300; + } + + /** + * Checks if the status code is valid. + * + * @return true if the status code is valid, false otherwise. + */ + public boolean isValid() { + return code >= 100 && code < 600; + } + + /** + * Sets the status code. + * + * @param code The HTTP status code. + */ + public void setCode(final int code) { + this.code = code; + } +} diff --git a/src/main/java/net/thauvin/erik/httpstatus/taglibs/ReasonTag.java b/src/main/java/net/thauvin/erik/httpstatus/taglibs/ReasonTag.java index 684449f..b862eac 100644 --- a/src/main/java/net/thauvin/erik/httpstatus/taglibs/ReasonTag.java +++ b/src/main/java/net/thauvin/erik/httpstatus/taglibs/ReasonTag.java @@ -79,6 +79,4 @@ public class ReasonTag extends XmlSupport { public void setCode(final int statusCode) { this.statusCode = statusCode; } - - } diff --git a/src/test/java/net/thauvin/erik/httpstatus/StatusCodeTest.java b/src/test/java/net/thauvin/erik/httpstatus/StatusCodeTest.java new file mode 100644 index 0000000..0ce8357 --- /dev/null +++ b/src/test/java/net/thauvin/erik/httpstatus/StatusCodeTest.java @@ -0,0 +1,76 @@ +/* + * StatusCodeTest.java + * + * Copyright (c) 2015-2021, Erik C. Thauvin (erik@thauvin.net) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of this project nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package net.thauvin.erik.httpstatus; + +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; +import org.testng.annotations.Test; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertFalse; +import static org.testng.Assert.assertTrue; + +/** + * StatusCode Tests. + * + * @author Erik C. Thauvin + */ +@SuppressFBWarnings("CE_CLASS_ENVY") +public class StatusCodeTest { + @Test + void testStatusCode() { + final StatusCode statusCode = new StatusCode(100); + + assertEquals(statusCode.getCode(), 100, "100 is 100"); + assertTrue(statusCode.isInfo(), "100 is informational"); + + statusCode.setCode(200); + assertEquals(statusCode.getCode(), 200, "200 is 200"); + assertTrue(statusCode.isSuccess(), "200 is OK"); + + statusCode.setCode(300); + assertTrue(statusCode.isRedirect(), "300 is redirect"); + + statusCode.setCode(400); + assertTrue(statusCode.isClientError(), "400 is client error"); + assertTrue(statusCode.isError(), "400 is error"); + + statusCode.setCode(500); + assertTrue(statusCode.isServerError(), "500 is server error"); + assertTrue(statusCode.isError(), "500 is error"); + assertEquals(statusCode.getReason(), Reasons.getReasonPhrase(500), "500 reason phrase"); + assertTrue(statusCode.isValid(), "500 is valid"); + + statusCode.setCode(600); + assertFalse(statusCode.isValid(), "600 is invalid()"); + } +}