This is an automated email from the ASF dual-hosted git repository.
thiagohp pushed a commit to branch rest
in repository https://gitbox.apache.org/repos/asf/tapestry-5.git
The following commit(s) were added to refs/heads/rest by this push:
new 569afe2 TAP5-2696: better HttpStatus and OpenAPI viewer styling
569afe2 is described below
commit 569afe24f66fe19ea3b13352d43937f96e135420
Author: Thiago H. de Paula Figueiredo <[email protected]>
AuthorDate: Fri Nov 19 16:09:09 2021 -0300
TAP5-2696: better HttpStatus and OpenAPI viewer styling
---
.../HttpStatusComponentEventResultProcessor.java | 4 +-
.../org/apache/tapestry5/services/HttpStatus.java | 169 +++++++++++++++++----
.../apache/tapestry5/services/HttpStatusTest.java | 128 ++++++++++++++++
.../tapestryopenapiviewer/pages/Index.tml | 8 +-
4 files changed, 271 insertions(+), 38 deletions(-)
diff --git
a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/HttpStatusComponentEventResultProcessor.java
b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/HttpStatusComponentEventResultProcessor.java
index 676c9f8..fabe617 100644
---
a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/HttpStatusComponentEventResultProcessor.java
+++
b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/HttpStatusComponentEventResultProcessor.java
@@ -45,10 +45,10 @@ public class HttpStatusComponentEventResultProcessor
implements ComponentEventRe
final String headerValue = extraHttpHeaders.get(header);
response.setHeader(header, headerValue);
}
- if (value.getMessage() != null)
+ if (value.getResponseBody() != null)
{
Objects.requireNonNull(value.getContentType(),
"HttpStatus.mimeType cannot be null");
-
response.getPrintWriter(value.getContentType()).append(value.getMessage()).close();
+
response.getPrintWriter(value.getContentType()).append(value.getResponseBody()).close();
}
}
}
diff --git
a/tapestry-core/src/main/java/org/apache/tapestry5/services/HttpStatus.java
b/tapestry-core/src/main/java/org/apache/tapestry5/services/HttpStatus.java
index bdc57b0..907f1c3 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/services/HttpStatus.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/services/HttpStatus.java
@@ -19,90 +19,163 @@ import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
+import javax.servlet.http.HttpServletResponse;
+
import org.apache.tapestry5.StreamResponse;
+import org.apache.tapestry5.http.Link;
/**
+ * <p>
* An event handler method may return an instance of this class to send an
specific HTTP status
* code to the client. It also supports providing a string to be used as the
response body
- * and extra HTTP headers to be set.
+ * and extra HTTP headers to be set. This class also provides some utility
+ * static methods for creating instances for specific HTTP statuses and a
fluent API for setting
+ * additional information on them.
+ * </p>
*
+ * <p>
* For returning binary content and/or adding a response header more than once
and/or
- * adding a response header without overwriting existing ones, implement a
{@link StreamResponse}
- * instead.
+ * adding a response header without overwriting existing ones, implementing a
{@link StreamResponse}
+ * is the most probable better choice.
+ * </p>
*
* @since 5.8.0
*/
public final class HttpStatus
{
private static final String CONTENT_LOCATION_HTTP_HEADER =
"Content-Location";
+
+ private static final String LOCATION_HTTP_HEADER = "Location";
private final int statusCode;
- String message;
+ private String responseBody;
- String contentType;
+ private String contentType;
- Map<String, String> extraHttpHeaders;
+ private Map<String, String> extraHttpHeaders;
/**
- * Creates an object with a given status code and no message.
+ * Creates an instance with status code <code>200 OK</code>.
*/
- public HttpStatus(int statusCode)
+ public static HttpStatus ok()
{
- this(statusCode, null, null);
+ return new HttpStatus(HttpServletResponse.SC_OK);
}
-
+
/**
- * Creates an object with a given status code, message and
<code>text/plain</code> MIME content type.
+ * Creates an instance with status code <code>201 Created</code>.
*/
- public HttpStatus(int statusCode, String message)
+ public static HttpStatus created()
{
- this(statusCode, message, "text/plain");
+ return new HttpStatus(HttpServletResponse.SC_CREATED);
}
/**
- * Creates an object with a given status code, message and MIME content
type.
+ * Creates an instance with status code <code>202 Accepted</code>.
*/
- public HttpStatus(int statusCode, String message, String contentType)
+ public static HttpStatus accepted()
{
- this.statusCode = statusCode;
- this.message = message;
- this.contentType = contentType;
+ return new HttpStatus(HttpServletResponse.SC_ACCEPTED);
}
-
+
/**
- * Returns the status code.
+ * Creates an instance with status code <code>303 See Other</code>.
+ * @param location the value of the <code>Location</code> header.
*/
- public int getStatusCode()
+ public static HttpStatus seeOther(String location)
{
- return statusCode;
+ return new
HttpStatus(HttpServletResponse.SC_SEE_OTHER).withLocation(location);
+ }
+
+ /**
+ * Creates an instance with status code <code>303 See Also</code>.
+ * @param location the value of the <code>Location</code> header.
+ */
+ public static HttpStatus seeOther(Link location)
+ {
+ return new
HttpStatus(HttpServletResponse.SC_SEE_OTHER).withLocation(location);
+ }
+
+ /**
+ * Creates an instance with status code <code>301 Moved Permanently</code>.
+ * @param location the value of the <code>Location</code> header.
+ */
+ public static HttpStatus movedPermanently(String location)
+ {
+ return new
HttpStatus(HttpServletResponse.SC_MOVED_PERMANENTLY).withLocation(location);
+ }
+
+ /**
+ * Creates an instance with status code <code>301 Moved Permanently</code>.
+ * @param location the value of the <code>Location</code> header.
+ */
+ public static HttpStatus movedPermanently(Link link)
+ {
+ return movedPermanently(link.toRedirectURI());
+ }
+
+ /**
+ * Creates an instance with status code <code>302 Found</code>.
+ * @param location the value of the <code>Location</code> header.
+ */
+ public static HttpStatus temporaryRedirect(String location)
+ {
+ return new
HttpStatus(HttpServletResponse.SC_FOUND).withLocation(location);
+ }
+
+ /**
+ * Creates an instance with status code <code>302 Found</code>.
+ * @param location the value of the <code>Location</code> header.
+ */
+ public static HttpStatus temporaryRedirect(Link location)
+ {
+ return temporaryRedirect(location.toRedirectURI());
}
/**
- * Returns the message.
+ * Creates an object with a given status code and no response body.
*/
- public String getMessage()
+ public HttpStatus(int statusCode)
{
- return message;
+ this(statusCode, null, null);
}
/**
- * Returns the extra HTTP headers.
+ * Creates an object with a given status code, response body and
<code>text/plain</code> MIME content type.
*/
- @SuppressWarnings("unchecked")
- public Map<String, String> getExtraHttpHeaders() {
- return extraHttpHeaders != null ? extraHttpHeaders :
Collections.EMPTY_MAP;
+ public HttpStatus(int statusCode, String responseBody)
+ {
+ this(statusCode, responseBody, "text/plain");
+ }
+
+ /**
+ * Creates an object with a given status code, response body and MIME
content type.
+ */
+ public HttpStatus(int statusCode, String responseBody, String contentType)
+ {
+ this.statusCode = statusCode;
+ this.responseBody = responseBody;
+ this.contentType = contentType;
}
/**
- * Returns the MIME content type of the message.
+ * Sets a redirect by using the <code>Location</code> HTTP header.
*/
- public String getContentType()
+ public HttpStatus withLocation(Link location)
{
- return contentType;
+ return withLocation(location.toRedirectURI());
}
/**
+ * Sets a redirect by using the <code>Location</code> HTTP header.
+ */
+ public HttpStatus withLocation(String location)
+ {
+ return withHttpHeader(LOCATION_HTTP_HEADER, location);
+ }
+
+ /**
* Sets the <code>Content-Location</code> HTTP header.
*/
public HttpStatus withContentLocation(String location)
@@ -127,4 +200,36 @@ public final class HttpStatus
return this;
}
+ /**
+ * Returns the status code.
+ */
+ public int getStatusCode()
+ {
+ return statusCode;
+ }
+
+ /**
+ * Returns the response body.
+ */
+ public String getResponseBody()
+ {
+ return responseBody;
+ }
+
+ /**
+ * Returns the MIME content type of the response body.
+ */
+ public String getContentType()
+ {
+ return contentType;
+ }
+
+ /**
+ * Returns the extra HTTP headers.
+ */
+ @SuppressWarnings("unchecked")
+ public Map<String, String> getExtraHttpHeaders() {
+ return extraHttpHeaders != null ? extraHttpHeaders :
Collections.EMPTY_MAP;
+ }
+
}
diff --git
a/tapestry-core/src/test/java/org/apache/tapestry5/services/HttpStatusTest.java
b/tapestry-core/src/test/java/org/apache/tapestry5/services/HttpStatusTest.java
new file mode 100644
index 0000000..a09ea82
--- /dev/null
+++
b/tapestry-core/src/test/java/org/apache/tapestry5/services/HttpStatusTest.java
@@ -0,0 +1,128 @@
+// Copyright 2021 The Apache Software Foundation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.apache.tapestry5.services;
+
+import org.apache.tapestry5.http.Link;
+import org.easymock.EasyMock;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+import static org.testng.Assert.assertEquals;
+
+import javax.servlet.http.HttpServletResponse;
+
+public class HttpStatusTest
+{
+
+ private static final String TEST_URL = "http://example.com/something";
+
+ private Link link;
+
+ @BeforeMethod
+ public void setupLink()
+ {
+ link = EasyMock.createMock(Link.class);
+ EasyMock.expect(link.toRedirectURI()).andReturn(TEST_URL).times(0, 1);
+ EasyMock.replay(link);
+ }
+
+ @AfterMethod
+ public void afterTest()
+ {
+ EasyMock.verify(link);
+ }
+
+ @Test
+ public void ok()
+ {
+ HttpStatus status = HttpStatus.ok();
+ assertEquals(status.getStatusCode(), HttpServletResponse.SC_OK);
+ }
+
+ @Test
+ public void created()
+ {
+ HttpStatus status = HttpStatus.created();
+ assertEquals(status.getStatusCode(), HttpServletResponse.SC_CREATED);
+ }
+
+ @Test
+ public void accepted()
+ {
+ HttpStatus status = HttpStatus.accepted();
+ assertEquals(status.getStatusCode(), HttpServletResponse.SC_ACCEPTED);
+ }
+
+ @Test
+ public void seeOtherWithString()
+ {
+ HttpStatus status = HttpStatus.seeOther(TEST_URL);
+ assertEquals(status.getStatusCode(), HttpServletResponse.SC_SEE_OTHER);
+ assertEquals(getLocation(status), TEST_URL);
+ }
+
+ @Test
+ public void seeOtherWithLink()
+ {
+ HttpStatus status = HttpStatus.seeOther(link);
+ assertEquals(status.getStatusCode(), HttpServletResponse.SC_SEE_OTHER);
+ }
+
+ @Test
+ public void movedPermanentlyWithString()
+ {
+ HttpStatus status = HttpStatus.movedPermanently(TEST_URL);
+ assertEquals(status.getStatusCode(),
HttpServletResponse.SC_MOVED_PERMANENTLY);
+ assertEquals(getLocation(status), TEST_URL);
+ }
+
+ @Test
+ public void movedPermanentlyWithLink()
+ {
+ HttpStatus status = HttpStatus.movedPermanently(link);
+ assertEquals(status.getStatusCode(),
HttpServletResponse.SC_MOVED_PERMANENTLY);
+ }
+
+ @Test
+ public void temporaryRedirectWithString()
+ {
+ HttpStatus status = HttpStatus.temporaryRedirect(TEST_URL);
+ assertEquals(status.getStatusCode(), HttpServletResponse.SC_FOUND);
+ assertEquals(getLocation(status), TEST_URL);
+ }
+
+ @Test
+ public void temporaryRedirectWithLink()
+ {
+ HttpStatus status = HttpStatus.temporaryRedirect(link);
+ assertEquals(status.getStatusCode(), HttpServletResponse.SC_FOUND);
+ }
+
+ @Test
+ public void withContentLocation()
+ {
+ HttpStatus status = HttpStatus.created().withContentLocation(TEST_URL);
+ assertEquals(getContentLocation(status), TEST_URL);
+ }
+
+ private String getLocation(HttpStatus status) {
+ return status.getExtraHttpHeaders().get("Location");
+ }
+
+ private String getContentLocation(HttpStatus status) {
+ return status.getExtraHttpHeaders().get("Content-Location");
+ }
+
+}
diff --git
a/tapestry-openapi-viewer/src/main/resources/org/apache/tapestry5/tapestryopenapiviewer/pages/Index.tml
b/tapestry-openapi-viewer/src/main/resources/org/apache/tapestry5/tapestryopenapiviewer/pages/Index.tml
index 06994c4..750b08d 100644
---
a/tapestry-openapi-viewer/src/main/resources/org/apache/tapestry5/tapestryopenapiviewer/pages/Index.tml
+++
b/tapestry-openapi-viewer/src/main/resources/org/apache/tapestry5/tapestryopenapiviewer/pages/Index.tml
@@ -32,7 +32,7 @@
}
pre.version
{
- color: black !important;
+ background-color: inherit;
}
.swagger-ui-attribution
{
@@ -82,11 +82,11 @@
<!-- alt="Online validator
badge"/> -->
<!-- </a> -->
<!-- </span> -->
+ <p class="swagger-ui-attribution">
+ This OpenAPI definition viewer is based on <a
href="https://swagger.io/tools/swagger-ui/">Swagger UI</a>.
+ </p>
</section>
</div>
</div>
- <p class="swagger-ui-attribution">
- This OpenAPI definition viewer is based on <a
href="https://swagger.io/tools/swagger-ui/">Swagger UI</a>.
- </p>
</body>
</html>
\ No newline at end of file