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();
}
Note:

The rename of the method from getBodyAsStream to newInputStream.

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()));
Note:

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);
}
Note:

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);
}
Note:

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, 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();
Note:

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();
Note:

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();
Note:

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();
Note:

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();
Note:

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);