com.pingidentity.pa.sdk.http
The body interface has changed to require an explicit read of data before invoking methods to obtain that data. Previously, methods to obtain the data would result in an implicit read of the data. The following code examples illustrate this change in semantics.
com.pingidentity.pa.sdk.http.Body
As the updated Javadocs for the body interface indicates, plugins should avoid interrogating a body object unless absolutely necessary because reading a body object’s data into memory can impact the scalability of PingAccess. As the plugin code is updated, evaluate whether the body object needs to be used by the plugin.
- Using the Body#read method
-
Before PingAccess 5.0:
private void invokeRead(Body body) throws IOException { body.read(); }
After PingAccess 5.0:
private void invokeRead(Body body) throws AccessException { try { body.read(); } catch (IOException e) { throw new AccessException("Failed to read body content", HttpStatus.BAD_GATEWAY, e); } }
- Using the Body#getContent method
-
Before PingAccess 5.0:
private void invokeGetContent(Body body) throws IOException { byte[] content = body.getContent(); }
After PingAccess 5.0:
private void invokeGetContent(Body body) throws AccessException { invokeRead(body); // see the Body#read code example for this method byte[] content = body.getContent(); }
- Using the Body#getBodyAsStream method
-
Before PingAccess 5.0:
private void invokeGetBodyAsStream(Body body) throws IOException { InputStream stream = body.getBodyAsStream(); }
After PingAccess 5.0:
private void invokeGetBodyAsStream(Body body) throws AccessException { invokeRead(body); // see the Body#read code example for this method InputStream stream = body.newInputStream(); }
The rename of the method from
getBodyAsStream
tonewInputStream
. - Using the Body#write method
-
Before PingAccess 5.0:
private void invokeWrite(Body body, BodyTransferrer bodyTransferrer) throws IOException { body.write(bodyTransferrer); }
After PingAccess 5.0:
This functionality is no longer supported. To obtain the content of the Body, read the content into memory using the Body#read method and then invoke Body#getContent or Body#newInputStream.
- Using the Body#getLength method
-
Before PingAccess 5.0:
private void invokeGetLength(Body body) throws IOException { int length = body.getLength(); }
After PingAccess 5.0:
private void invokeGetLength(Body body) throws AccessException { invokeRead(body); // see the Body#read code example for this method int length = body.getLength(); }
- Using the Body#getRaw method
-
Before PingAccess 5.0:
private void invokeGetRaw(Body body) throws IOException { byte[] rawBody = body.getRaw(); }
After PingAccess 5.0:
This functionality is no longer supported. This method used to provide access to the content as it appeared on the wire, which required complicated handling if the body content used a chunked Transfer-Encoding. Use Body#getContent instead.
com.pingidentity.pa.sdk.http.BodyFactory
- Using the BodyFactory#continuousBody method
-
Before PingAccess 5.0:
private void invokeContinuousBody(BodyFactory bodyFactory, byte[] content) { Body body = bodyFactory.continuousBody(content); }
After PingAccess 5.0:
private void invokeContinuousBody(BodyFactory bodyFactory, byte[] content) { Body body = bodyFactory.createInMemoryBody(content); }
Before PingAccess 5.0:
private void invokeContinuousBody(BodyFactory bodyFactory, InputStream in) { Body body = bodyFactory.continuousBody(in); }
After PingAccess 5.0:
A Body instance can no longer be created from an InputStream using the BodyFactory class. Instead, a plugin should read the contents of the InputStream into a byte array and provide the byte array to BodyFactory#createInMemoryBody.
com.pingidentity.pa.sdk.http.Constants
The constants available from this class have been removed from the SDK. Plugins using these constants should maintain their own constants with the needed values.
com.pingidentity.pa.sdk.http.Exchange
A handful of methods have been removed from the Exchange.
Further, the mechanism for storing data on the exchange through properties has been enhanced to make it easier to write type-safe code when working with Exchange properties.
- Using the Exchange#getCreationTime method
-
Before PingAccess 5.0:
Calendar creationTime = exchange.getCreationTime();
After PingAccess 5.0:
Calendar creationTime = Calendar.getInstance(); creationTime.setTime(Date.from(exchange.getCreationTime()));
If a Calendar object is not required, consider using the Instant object returned from the getCreationTime method directly instead of converting it into a Calendar object.
- Using the Exchange#getDestinations method
-
Before PingAccess 5.0:
List<String> destinations = exchange.getDestinations();
After PingAccess 5.0:
This functionality is no longer supported. Consider using the Exchange#getTargetHosts method to obtain similar information from the Exchange.
- Using the Exchange#getOriginalHostHeader method
-
Before PingAccess 5.0:
String originalHostHeader = exchange.getOriginalHostHeader();
After PingAccess 5.0:
This functionality is no longer supported. Consider using the Exchange#getUserAgentHost method to obtain similar information from the Exchange. The getUserAgentHost method leverages the PingAccess HTTP requests configuration to determine the Host header value sent by the user agent.
- Using the Exchange#getOriginalHostHeaderHost method
-
Before PingAccess 5.0:
String host = exchange.getOriginalHostHeaderHost();
After PingAccess 5.0:
This functionality is no longer supported. Consider using the Exchange#getUserAgentHost method to obtain similar information from the Exchange. The getUserAgentHost method leverages the PingAccess HTTP requests configuration to determine the Host header value sent by the user agent.
- Using the Exchange#getOriginalHostHeaderPort method
-
Before PingAccess 5.0:
String port = exchange.getOriginalHostHeaderPort();
After PingAccess 5.0:
This functionality is no longer supported. Consider using the Exchange#getUserAgentHost method to obtain similar information from the Exchange. The getUserAgentHost method leverages the PingAccess HTTP requests configuration to determine the Host header value sent by the user agent.
- Using the Exchange#getOriginalRequestBaseUri method
-
Before PingAccess 5.0:
String originalRequestBaseUri = exchange.getOriginalRequestBaseUri();
After PingAccess 5.0:
This functionality is no longer supported. A possible replacement is as follows:
String originalRequestBaseUri = exchange.getUserAgentProtocol() + "://" + exchange.getUserAgentHost();
- Using the Exchange#getProperties method
-
Before PingAccess 5.0:
Map<String, String> properties = exchange.getProperties();
After PingAccess 5.0:
This functionality is no longer supported. Properties should be obtained individually from the Exchange.
- Using the Exchange#getRequestBaseUri method
-
Before PingAccess 5.0:
String requestBaseUri = exchange.getRequestBaseUri();
After PingAccess 5.0:
This functionality is no longer supported. A possible replacement is as follows.
String requestBaseUri = exchange.getUserAgentProtocol() + "://" + exchange.getUserAgentHost();
- Using the Exchange#getRequestScheme method
-
Before PingAccess 5.0:
String requestScheme = exchange.getRequestScheme();
After PingAccess 5.0:
This functionality is no longer supported. A possible replacement is as follows.
String requestScheme = exchange.getUserAgentProtocol() + "://";
- Using the Exchange#getUser method
-
Before PingAccess 5.0:
private void invokeSetUser(Exchange exchange, User user) { exchange.setUser(user); }
After PingAccess 5.0:
This functionality is no longer supported. The identity associated with an Exchange cannot be replaced.
- Using the Exchange#setUser method
-
Before PingAccess 5.0:
private void invokeSetUser(Exchange exchange, User user) { exchange.setUser(user); }
After PingAccess 5.0:
This functionality is no longer supported. The identity associated with an Exchange cannot be replaced.
- Using the Exchange#setSourceIp method
-
Before PingAccess 5.0:
private void invokeSetSourceIp(Exchange exchange, String sourceIp) { exchange.setSourceIp(sourceIp); }
After PingAccess 5.0:
This functionality is no longer supported. This value cannot be changed.
- Using the Exchange#setProperty method
-
Before PingAccess 5.0:
private void invokeSetProperty(Exchange exchange, String propertyKey, String value) { exchange.setProperty(propertyKey, value); }
After PingAccess 5.0:
private void invokeSetProperty(Exchange exchange, ExchangeProperty<String> propertyKey, String value) { exchange.setProperty(propertyKey, value); }
See the Javadocs for ExchangeProperty for instructions on creating an ExchangeProperty object.
- Using the Exchange#getProperty method
-
Before PingAccess 5.0:
private void invokeGetProperty(Exchange exchange, String propertyKey) { Object propertyValueObj = exchange.getProperty(propertyKey); if (propertyValueObj instanceof String) { String propertyValue = (String) propertyValueObj; } }
After PingAccess 5.0:
private void invokeGetProperty(Exchange exchange, ExchangeProperty<String> propertyKey) { String propertyValue = exchange.getProperty(propertyKey).orElse(null); }
Exchange#getProperty now returns an Optional object instead of the Object directly.
com.pingidentity.pa.sdk.http.Header
This deprecated class has been replaced by the Headers interface. A Headers object can be created using a HeadersFactory obtained from the ServiceFactory#headersFactory method. The majority of methods on Header have counterparts on the Headers interface. See the Javadocs for the Headers interface for more information.
com.pingidentity.pa.sdk.http.HeaderField
This class is now final and cannot be extended.
- Constructing a HeaderField
-
Before PingAccess 5.0:
private HeaderField createHeaderField(String line) { return new HeaderField(line); }
After PingAccess 5.0:
private HeaderField createHeaderField(String line) { String name = line.substring(0, line.indexOf(':')); String value = (line.substring(line.indexOf(":") + 1)).trim(); return new HeaderField(name, value); }
Parsing an HTTP header field line can be error prone, consider if the plugin can avoid having to parse an HTTP header field line.
- Using the HeaderField#setHeaderName method
-
Before PingAccess 5.0:
private void invokeSetHeaderName(HeaderField field) { field.setHeaderName(new HeaderName("X-Custom")); }
After PingAccess 5.0:
This functionality is no longer supported. A HeaderField’s name is set upon construction and cannot be changed.
- Using the HeaderField#getApproximateSize method
-
Before PingAccess 5.0:
int approximateSize = field.getApproximateSize();
After PingAccess 5.0:
This method has been removed. The value returned by the method can still be computed:
int approximateSize = 2 * (4 + field.getHeaderName().toString().length() + field.getValue().length());
com.pingidentity.pa.sdk.http.Headers
A few methods on the Headers interface have been updated to use the instant class, instead of date.
- Using the Headers#getDate method
-
Before PingAccess 5.0:
Date date = headers.getDate();
After PingAccess 5.0:
Date date = Date.from(headers.getDate());
- Using the Headers#setDate method
-
Before PingAccess 5.0:
private void invokeSetDate(Headers headers, Date date) { headers.setDate(date); }
After PingAccess 5.0:
private void invokeSetDate(Headers headers, Date date) { headers.setDate(date.toInstant()); }
- Using the Headers#getLastModified method
-
Before PingAccess 5.0:
SimpleDateFormat format = new SimpleDateFormat("E, dd MMM yyyy HH:mm:ss z", Locale.ENGLISH); String lastModified = headers.getLastModified(); if (lastModified != null) { Date lastModifiedDate = format.parse(lastModified); }
After PingAccess 5.0:
Date lastModifiedDate = Date.from(headers.getLastModified());
- Using the Headers#setLastModified method
-
Before PingAccess 5.0:
private void invokeSetLastModified(Headers headers, Date date) { SimpleDateFormat format = new SimpleDateFormat("E, dd MMM yyyy HH:mm:ss z", Locale.ENGLISH); headers.setLastModified(format.format(date)); }
After PingAccess 5.0:
private void invokeSetLastModified(Headers headers, Date date) { headers.setLastModified(date.toInstant()); }
com.pingidentity.pa.sdk.http.HeadersFactory
- Using the HeadersFactory#createFromRawHeaderFields method
-
Before PingAccess 5.0:
private void invokeCreateFromRawHeaderFields(HeadersFactory factory, List<String> fields) throws ParseException { Headers headers = factory.createFromRawHeaderFields(fields); }
After PingAccess 5.0:
This functionality is no longer supported. Consider if the plugin can create HeaderFields directly and utilize the HeadersFactory#create method.
com.pingidentity.pa.sdk.http.HttpStatus
The HttpStatus enum was converted to a final class. Common HttpStatus instances are defined as constants on HttpStatus.
- Using the HttpStatus#getLocalizationKey method
-
Before PingAccess 5.0:
String localizationKey = status.getLocalizationKey();
After PingAccess 5.0:
This functionality is no longer supported. Instead, a HttpStatus contains a LocalizedMessage instance that encapsulates the localization of the status message for use in error templates.
com.pingidentity.pa.sdk.http.MimeType
The constants available in this class are now available as constant MediaType instances in the class com.pingidentity.pa.sdk.http.CommonMediaTypes.
com.pingidentity.pa.sdk.http.MediaType
This class is now final and cannot be extended.
- Constructing a MediaType
-
Before PingAccess 5.0:
private void createMediaType(String mediaTypeString) { MediaType mediaType = new MediaType(mediaTypeString); }
After PingAccess 5.0:
private void createMediaType(String mediaTypeString) { MediaType mediaType = MediaType.parse(mediaTypeString); }
com.pingidentity.pa.sdk.http.Message
A number of methods have been removed from the Message interface.
- Using the Message#getBodyAsStream method
-
Before PingAccess 5.0:
InputStream bodyStream = message.getBodyAsStream();
After PingAccess 5.0:
This functionality is no longer supported. However, the following code snippet can be used to maintain semantics of the old method.
Body body = message.getBody(); try { body.read(); } catch (IOException | AccessException e) { throw new RuntimeException("Could not get body as stream", e); } InputStream bodyStream = body.newInputStream();
While this snippet maintains semantics, enable a plugin to propagate errors as an AccessException instead of as a RuntimeException.
- Using the Message#getCharset method
-
Before PingAccess 5.0:
Charset charset = message.getCharset();
After PingAccess 5.0:
This functionality is no longer supported. However, the following code snippet can be used to maintain semantics of the old method.
Charset charset = message.getHeaders().getCharset(); if (charset == null) { charset = StandardCharsets.UTF_8; }
While this snippet maintains semantics, a plugin should consider how to handle the case where a Charset is not specified by a Message’s header fields. Assuming a Charset of UTF-8 might lead to issues in some cases.
- Using the Message#getHeader method
-
Before PingAccess 5.0:
Header header = message.getHeader();
After PingAccess 5.0:
This functionality is no longer supported. Instead, use Message#getHeaders and the Headers interface instead of Header.
- Using the Message#setHeader method
-
Before PingAccess 5.0:
private void invokeSetHeader(Message message, Header header) { message.setHeader(header); }
After PingAccess 5.0:
This functionality is no longer supported. Instead, use Message#setHeaders and the Headers interface instead of Header.
- Using the Message#isDeflate method
-
Before PingAccess 5.0:
boolean deflate = message.isDeflate();
After PingAccess 5.0:
This method has been removed. However, the value can still be computed with the following code snippet.
List<String> contentEncodingValues = message.getHeaders().getContentEncoding(); boolean deflate = contentEncodingValues.stream().anyMatch(v -> v.equalsIgnoreCase("deflate")) && contentEncodingValues.size() == 1;
- Using the Message#isGzip method
-
Before PingAccess 5.0:
boolean gzip = message.isGzip();
After PingAccess 5.0:
This method has been removed. However, the value can still be computed with the following code snippet.
List<String> contentEncodingValues = message.getHeaders().getContentEncoding(); boolean gzip = contentEncodingValues.stream().anyMatch(v -> v.equalsIgnoreCase("gzip")) && contentEncodingValues.size() == 1;
- Using the Message#isHTTP10 method
-
Before PingAccess 5.0:
boolean http10 = message.isHTTP10();
After PingAccess 5.0:
This method has been removed. However, the value can still be computed with the following code snippet.
boolean http10 = message.getVersion().equals("1.0");
- Using the Message#isHTTP11 method
-
Before PingAccess 5.0:
boolean http11 = message.isHTTP11();
After PingAccess 5.0:
The method has been removed. However, the value can still be computed with the following code snippet.
boolean http11 = message.getVersion().equals("1.1");
- Using the Message#read method
-
Before PingAccess 5.0:
private void invokeRead(Message message, InputStream inputStream, boolean createBody) throws IOException { message.read(inputStream, createBody); }
After PingAccess 5.0:
This functionality is no longer supported. A request attached to an exchange can no longer be completely replaced, but individual components can be replaced, such as the method, Uniform Resource Identifier (URI), headers and body. A response attached to an exchange can be replaced by using Exchange#setResponse.
- Using the Message#setVersion method
-
Before PingAccess 5.0:
private void invokeSetVersion(Message message, String version) { message.setVersion(version); }
After PingAccess 5.0:
This functionality is no longer supported. The version of a message cannot be changed.
- Using the Message#write method
-
Before PingAccess 5.0:
private void invokeWrite(Message message, OutputStream output) throws IOException { message.write(output); }
After PingAccess 5.0:
This functionality is no longer supported. However, the following code snippet can be used to perform the equivalent operation.
private void invokeWrite(Message message, OutputStream output) throws IOException, AccessException { Body body = message.getBody(); body.read(); output.write(message.getStartLine().getBytes(StandardCharsets.ISO_8859_1)); output.write(message.getHeaders().toString().getBytes(StandardCharsets.ISO_8859_1)); output.write("\r\n".getBytes(StandardCharsets.ISO_8859_1)); output.write(body.getContent()); output.flush(); }
com.pingidentity.pa.sdk.http.Method
The method interface has been converted to a final class. Additionally, the related methods enum has been merged into the method class. The method class provides common method instances as class-level constants.
- Obtaining a common Method instance
-
Before PingAccess 5.0:
Method get = Methods.GET
After PingAccess 5.0:
Method get = Method.GET;
- Using the Method#getMethodName method
-
Before PingAccess 5.0:
String methodName = method.getMethodName();
After PingAccess 5.0:
String methodName = method.getName();
com.pingidentity.pa.sdk.http.Request
A few methods have been removed from the request interface.
- Using the Request#getPostParams method
-
Before PingAccess 5.0:
private void invokeGetPostParams(Request request) throws IOException { Map<String, String[]> postParams = request.getPostParams(); }
After PingAccess 5.0:
private void invokeGetPostParams(Request request) throws AccessException { Body body = request.getBody(); try { body.read(); } catch (IOException e) { throw new AccessException("Failed to read body content", HttpStatus.BAD_GATEWAY, e); } Map<String, String[]> postParams = body.parseFormParams(); }
- Using the Request#isMultipartFormPost method
-
Before PingAccess 5.0:
boolean multipartFormPost = request.isMultipartFormPost();
After PingAccess 5.0:
This method has been removed from the Request interface. However, the value can still be calculated using the following code snippet.
Headers headers = request.getHeaders(); boolean multipartFormPost = request.getMethod() == Method.POST && headers.getContentType() != null && headers.getContentType().getBaseType().equals("multipart/form-data") && headers.getContentType().getParameter("boundary") != null;
com.pingidentity.pa.sdk.http.ResponseBuilder
A handful of methods were removed from ResponseBuilder. Additionally, a handful of methods have changed their semantics, particularly those that included an HTML message payload. See the updated Javadocs for ResponseBuilder for more info.
- Using the ResponseBuilder#badRequestText method
-
Before PingAccess 5.0:
Response response = ResponseBuilder.badRequestText(message).build();
After PingAccess 5.0:
Response response = ResponseBuilder.newInstance(HttpStatus.BAD_REQUEST) .contentType(CommonMediaTypes.TEXT_PLAIN) .body(message) .build();
This approach does not localize the response body. Using a TemplateRenderer is recommended instead.
- Using the ResponseBuilder#contentLength method
-
Before PingAccess 5.0:
Response response = ResponseBuilder.newInstance().contentLength(length).build();
After PingAccess 5.0:
This functionality is no longer supported. Consider using one of the ResponseBuilder#body methods instead of explicitly setting the content length. This ensures that the body content of the Response aligns with the Content-Length header field.
- Using the ResponseBuilder#continue100 method
-
Before PingAccess 5.0:
Response response = ResponseBuilder.continue100().build();
After PingAccess 5.0:
Response response = ResponseBuilder.newInstance(HttpStatus.CONTINUE).build();
- Using the ResponseBuilder#forbiddenText method
-
Before PingAccess 5.0:
Response response = ResponseBuilder.forbiddenText().build();
After PingAccess 5.0:
Response response = ResponseBuilder.newInstance(HttpStatus.FORBIDDEN) .contentType(CommonMediaTypes.TEXT_PLAIN) .body(HttpStatus.FORBIDDEN.getMessage()) .build();
This approach does not localize the response body. Use a TemplateRenderer instead.
- Using the ResponseBuilder#forbiddenWithoutBody method
-
Before PingAccess 5.0:
Response response = ResponseBuilder.forbiddenWithoutBody().build();
After PingAccess 5.0:
Response response = ResponseBuilder.newInstance(HttpStatus.FORBIDDEN).build();
Before PingAccess 5.0:
Response response = ResponseBuilder.forbiddenWithoutBody(message).build();
After PingAccess 5.0:
Response response = ResponseBuilder.newInstance(HttpStatus.FORBIDDEN).build();
In the original method, the string message parameter was not used.
- Using the ResponseBuilder#htmlMessage method
-
Before PingAccess 5.0:
String message = ResponseBuilder.htmlMessage(caption, text);
After PingAccess 5.0:
This functionality is no longer supported. Plugins that used this method will need to construct the HTML message without this method. Consider using the TemplateRenderer utility class in place of this method.
- Using the ResponseBuilder#internalServerError method
-
Before PingAccess 5.0:
Response response = ResponseBuilder.internalServerError(message).build();
After PingAccess 5.0:
Response response = ResponseBuilder.internalServerError().body(message).build();
This approach does not localize the response body. Use a TemplateRenderer instead.
- Using the ResponseBuilder#internalServerErrorWithoutBody method
-
Before PingAccess 5.0:
Response response = ResponseBuilder.internalServerErrorWithoutBody().build();
After PingAccess 5.0:
Response response = ResponseBuilder.internalServerError().build();
- Using the ResponseBuilder#newInstance method
-
The no-arg newInstance method has been removed. A HttpStatus is required to create an instance of ResponseBuilder, and the required HttpStatus object should be passed to the newInstance method that accepts a HttpStatus.Before PingAccess 5.0:
Response response = ResponseBuilder.newInstance().build()
After PingAccess 5.0:
Response response = ResponseBuilder.newInstance(HttpStatus.INTERNAL_SERVER_ERROR).build();
- Using the ResponseBuilder#noContent method
-
Before PingAccess 5.0:
Response response = ResponseBuilder.noContent().build();
After PingAccess 5.0:
Response response = ResponseBuilder.newInstance(HttpStatus.NO_CONTENT).build();
- Using the ResponseBuilder#notFoundWithoutBody method
-
Before PingAccess 5.0:
Response response = ResponseBuilder.notFoundWithoutBody().build();
After PingAccess 5.0:
Response response = ResponseBuilder.notFound().build();
- Using the ResponseBuilder#serverUnavailable method
-
Before PingAccess 5.0:
Response response = ResponseBuilder.serverUnavailable(message).build();
After PingAccess 5.0:
Response response = ResponseBuilder.serviceUnavailable().body(message).build();
This approach does not localize the response body. Use a TemplateRenderer instead.
- Using the ResponseBuilder#serviceUnavailableWithoutBody method
-
Before PingAccess 5.0:
Response response = ResponseBuilder.serverUnavailableWithoutBody().build();
After PingAccess 5.0:
Response response = ResponseBuilder.serviceUnavailable().build();
- Using the ResponseBuilder#status method
-
The status methods have been removed. Instead the status should be specified to the newInstance method as it is now required.Before PingAccess 5.0:
Response response = ResponseBuilder.newInstance().status(HttpStatus.OK).build();
After PingAccess 5.0:
Response response = ResponseBuilder.newInstance(HttpStatus.OK).build();
- Using the ResponseBuilder#unauthorizedWithoutBody method
-
Before PingAccess 5.0:
Response response = ResponseBuilder.unauthorizedWithoutBody().build();
After PingAccess 5.0:
Response response = ResponseBuilder.unauthorized().build();
com.pingidentity.pa.sdk.http.Response
A few methods were removed from the response interface.
- Using the Response#isRedirect method
-
Before PingAccess 5.0:
boolean redirect = response.isRedirect();
After PingAccess 5.0:
boolean redirect = response.getStatusCode() >= 300 && response.getStatusCode() < 400;
- Using the Response#setStatusCode method
-
Before PingAccess 5.0:
response.setStatusCode(HttpStatus.OK.getCode());
After PingAccess 5.0:
response.setStatus(HttpStatus.OK);
- Using the Response#setStatusMessage method
-
Before PingAccess 5.0:
response.setStatusMessage(HttpStatus.OK.getMessage());
After PingAccess 5.0:
response.setStatus(HttpStatus.OK);