All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.juneau.rest.client.ResponseHeader Maven / Gradle / Ivy

// ***************************************************************************************************************************
// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file *
// * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file        *
// * to you 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.juneau.rest.client;

import static org.apache.juneau.common.internal.ThrowableUtils.*;
import static org.apache.juneau.httppart.HttpPartType.*;
import static org.apache.juneau.internal.ClassUtils.*;
import static org.apache.juneau.internal.CollectionUtils.*;

import java.lang.reflect.*;
import java.time.*;
import java.util.*;
import java.util.regex.*;

import org.apache.http.*;
import org.apache.juneau.*;
import org.apache.juneau.assertions.*;
import org.apache.juneau.http.header.*;
import org.apache.juneau.httppart.*;
import org.apache.juneau.oapi.*;
import org.apache.juneau.parser.ParseException;
import org.apache.juneau.reflect.*;
import org.apache.juneau.rest.client.assertion.*;

/**
 * Represents a single header on an HTTP response.
 *
 * 

* An extension of an HttpClient {@link Header} that provides various support for converting the header to POJOs and * other convenience methods. * *

See Also:
*/ public class ResponseHeader extends BasicHeader { private static final long serialVersionUID = 1L; static final Header NULL_HEADER = new Header() { @Override /* Header */ public String getName() { return null; } @Override /* Header */ public String getValue() { return null; } @Override /* Header */ public HeaderElement[] getElements() throws org.apache.http.ParseException { return new HeaderElement[0]; } }; private final HeaderElement[] elements; private final RestRequest request; private final RestResponse response; private HttpPartParserSession parser; private HttpPartSchema schema; /** * Constructor. * @param name The header name. * @param request The request object. * @param response The response object. * @param header The wrapped header. Can be null. * @throws IllegalArgumentException If name is null or empty. */ public ResponseHeader(String name, RestRequest request, RestResponse response, Header header) { super(name, header == null ? null : header.getValue()); this.request = request; this.response = response; this.elements = header == null ? new HeaderElement[0] : header.getElements(); parser(null); } //------------------------------------------------------------------------------------------------------------------ // Setters //------------------------------------------------------------------------------------------------------------------ /** * Specifies the part schema for this header. * *

* Used by schema-based part parsers such as {@link OpenApiParser}. * * @param value * The part schema. * @return This object. */ public ResponseHeader schema(HttpPartSchema value) { this.schema = value; return this; } /** * Specifies the part parser to use for this header. * *

* If not specified, uses the part parser defined on the client by calling {@link RestClient.Builder#partParser(Class)}. * * @param value * The new part parser to use for this header. *
If null, {@link SimplePartParser#DEFAULT} will be used. * @return This object. */ public ResponseHeader parser(HttpPartParserSession value) { this.parser = value == null ? SimplePartParser.DEFAULT_SESSION : value; return this; } //------------------------------------------------------------------------------------------------------------------ // Retrievers //------------------------------------------------------------------------------------------------------------------ /** * Returns the value of this header as an integer. * * @return The value of this header as an integer, or {@link Optional#empty()} if the header was not present. */ public Optional asInteger() { return asIntegerHeader().asInteger(); } /** * Returns the value of this header as a boolean. * * @return The value of this header as a boolean, or {@link Optional#empty()} if the header was not present. */ public Optional asBoolean() { return asBooleanHeader().asBoolean(); } /** * Returns the value of this header as a long. * * @return The value of this header as a long, or {@link Optional#empty()} if the header was not present. */ public Optional asLong() { return asLongHeader().asLong(); } /** * Returns the value of this header as a date. * * @return The value of this header as a date, or {@link Optional#empty()} if the header was not present. */ public Optional asDate() { return asDateHeader().asZonedDateTime(); } /** * Returns the value of this header as a list from a comma-delimited string. * * @return The value of this header as a list from a comma-delimited string, or {@link Optional#empty()} if the header was not present. */ public Optional asCsvArray() { return asCsvHeader().asArray(); } /** * Returns the value of this header as a {@link BasicHeader}. * * @param c The subclass of {@link BasicHeader} to instantiate. * @param The subclass of {@link BasicHeader} to instantiate. * @return The value of this header as a string, never null. */ public T asHeader(Class c) { try { ClassInfo ci = ClassInfo.of(c); ConstructorInfo cc = ci.getPublicConstructor(x -> x.hasParamTypes(String.class)); if (cc != null) return cc.invoke(getValue()); cc = ci.getPublicConstructor(x -> x.hasParamTypes(String.class, String.class)); if (cc != null) return cc.invoke(getName(), getValue()); } catch (Throwable e) { if (e instanceof ExecutableException) e = ((ExecutableException)e).getCause(); throw asRuntimeException(e); } throw new BasicRuntimeException("Could not determine a method to construct type {0}", className(c)); } /** * Returns the value of this header as a CSV array header. * * @return The value of this header as a CSV array header, never null. */ public BasicCsvHeader asCsvHeader() { return new BasicCsvHeader(getName(), getValue()); } /** * Returns the value of this header as a date header. * * @return The value of this header as a date header, never null. */ public BasicDateHeader asDateHeader() { return new BasicDateHeader(getName(), getValue()); } /** * Returns the value of this header as an entity validator array header. * * @return The value of this header as an entity validator array header, never null. */ public BasicEntityTagsHeader asEntityTagsHeader() { return new BasicEntityTagsHeader(getName(), getValue()); } /** * Returns the value of this header as an entity validator header. * * @return The value of this header as an entity validator array, never null. */ public BasicEntityTagHeader asEntityTagHeader() { return new BasicEntityTagHeader(getName(), getValue()); } /** * Returns the value of this header as an integer header. * * @return The value of this header as an integer header, never null. */ public BasicIntegerHeader asIntegerHeader() { return new BasicIntegerHeader(getName(), getValue()); } /** * Returns the value of this header as an boolean header. * * @return The value of this header as an boolean header, never null. */ public BasicBooleanHeader asBooleanHeader() { return new BasicBooleanHeader(getName(), getValue()); } /** * Returns the value of this header as a long header. * * @return The value of this header as a long header, never null. */ public BasicLongHeader asLongHeader() { return new BasicLongHeader(getName(), getValue()); } /** * Returns the value of this header as a range array header. * * @return The value of this header as a range array header, never null. */ public BasicStringRangesHeader asStringRangesHeader() { return new BasicStringRangesHeader(getName(), getValue()); } /** * Returns the value of this header as a string header. * * @return The value of this header as a string header, never null. */ public BasicStringHeader asStringHeader() { return new BasicStringHeader(getName(), getValue()); } /** * Returns the value of this header as a URI header. * * @return The value of this header as a URI header, never null. */ public BasicUriHeader asUriHeader() { return new BasicUriHeader(getName(), getValue()); } /** * Same as {@link #asString()} but sets the value in a mutable for fluent calls. * * @param value The mutable to set the header value in. * @return This object. */ public RestResponse asString(Value value) { value.set(orElse(null)); return response; } /** * Converts this header to the specified type. * *

* See Complex Data Types for information on defining complex generic types of {@link Map Maps} and {@link Collection Collections}. * * @param The type to convert to. * @param type The type to convert to. * @param args The type parameters. * @return The converted type, or null if header is not present. */ public Optional as(Type type, Type...args) { return as(request.getClassMeta(type, args)); } /** * Same as {@link #as(Type,Type...)} but sets the value in a mutable for fluent calls. * *

* See Complex Data Types for information on defining complex generic types of {@link Map Maps} and {@link Collection Collections}. * * @param value The mutable to set the parsed header value in. * @param The type to convert to. * @param type The type to convert to. * @param args The type parameters. * @return This object. */ @SuppressWarnings("unchecked") public RestResponse as(Value value, Type type, Type...args) { value.set((T)as(type, args).orElse(null)); return response; } /** * Converts this header to the specified type. * * @param The type to convert to. * @param type The type to convert to. * @return The converted type, or null if header is not present. */ public Optional as(Class type) { return as(request.getClassMeta(type)); } /** * Same as {@link #as(Class)} but sets the value in a mutable for fluent calls. * * @param value The mutable to set the parsed header value in. * @param The type to convert to. * @param type The type to convert to. * @return This object. */ public RestResponse as(Value value, Class type) { value.set(as(type).orElse(null)); return response; } /** * Converts this header to the specified type. * * @param The type to convert to. * @param type The type to convert to. * @return The converted type, or null if header is not present. */ public Optional as(ClassMeta type) { try { return optional(parser.parse(HEADER, schema, getValue(), type)); } catch (ParseException e) { throw new BasicRuntimeException(e, "Could not parse response header {0}.", getName()); } } /** * Same as {@link #as(ClassMeta)} but sets the value in a mutable for fluent calls. * * @param value The mutable to set the parsed header value in. * @param The type to convert to. * @param type The type to convert to. * @return This object. */ public RestResponse as(Value value, ClassMeta type) { value.set(as(type).orElse(null)); return response; } /** * Matches the specified pattern against this header value. * *

Example:
*

* // Parse header using a regular expression. * Matcher matcher = client * .get(URI) * .run() * .getResponseHeader("Content-Type").asMatcher(Pattern.compile("application/(.*)")); * * if (matcher.matches()) { * String mediaType = matcher.group(1); * } *

* * @param pattern The regular expression pattern to match. * @return The matcher. */ public Matcher asMatcher(Pattern pattern) { return pattern.matcher(orElse("")); } /** * Matches the specified pattern against this header value. * *
Example:
*

* // Parse header using a regular expression. * Matcher matcher = client * .get(URI) * .run() * .getHeader("Content-Type").asMatcher("application/(.*)"); * * if (matcher.matches()) { * String mediaType = matcher.group(1); * } *

* * @param regex The regular expression pattern to match. * @return The matcher. */ public Matcher asMatcher(String regex) { return asMatcher(regex, 0); } /** * Matches the specified pattern against this header value. * *
Example:
*

* // Parse header using a regular expression. * Matcher matcher = client * .get(URI) * .run() * .getHeader("Content-Type").asMatcher("application/(.*)", CASE_INSENSITIVE); * * if (matcher.matches()) { * String mediaType = matcher.group(1); * } *

* * @param regex The regular expression pattern to match. * @param flags Pattern match flags. See {@link Pattern#compile(String, int)}. * @return The matcher. */ public Matcher asMatcher(String regex, int flags) { return asMatcher(Pattern.compile(regex, flags)); } //------------------------------------------------------------------------------------------------------------------ // Assertions //------------------------------------------------------------------------------------------------------------------ /** * Provides the ability to perform fluent-style assertions on this response header. * *
Examples:
*

* // Validates the content type header is provided. * client * .get(URI) * .run() * .getHeader("Content-Type").assertValue().exists(); * * // Validates the content type is JSON. * client * .get(URI) * .run() * .getHeader("Content-Type").assertValue().equals("application/json"); * * // Validates the content type is JSON using test predicate. * client * .get(URI) * .run() * .getHeader("Content-Type").assertValue().is(x -> x.equals("application/json")); * * // Validates the content type is JSON by just checking for substring. * client * .get(URI) * .run() * .getHeader("Content-Type").assertValue().contains("json"); * * // Validates the content type is JSON using regular expression. * client * .get(URI) * .run() * .getHeader("Content-Type").assertValue().isPattern(".*json.*"); * * // Validates the content type is JSON using case-insensitive regular expression. * client * .get(URI) * .run() * .getHeader("Content-Type").assertValue().isPattern(".*json.*", CASE_INSENSITIVE); *

* *

* The assertion test returns the original response object allowing you to chain multiple requests like so: *

* // Validates the header and converts it to a bean. * MediaType mediaType = client * .get(URI) * .run() * .getHeader("Content-Type").assertValue().isNotEmpty() * .getHeader("Content-Type").assertValue().isPattern(".*json.*") * .getHeader("Content-Type").as(MediaType.class); *

* * @return A new fluent assertion object. */ public FluentResponseHeaderAssertion assertValue() { return new FluentResponseHeaderAssertion<>(this, this); } /** * Shortcut for calling assertValue().asString(). * * @return A new fluent assertion. */ public FluentStringAssertion assertString() { return new FluentResponseHeaderAssertion<>(this, this).asString(); } /** * Shortcut for calling assertValue().asInteger(). * * @return A new fluent assertion. */ public FluentIntegerAssertion assertInteger() { return new FluentResponseHeaderAssertion<>(this, this).asInteger(); } /** * Shortcut for calling assertValue().asLong(). * * @return A new fluent assertion. */ public FluentLongAssertion assertLong() { return new FluentResponseHeaderAssertion<>(this, this).asLong(); } /** * Shortcut for calling assertValue().asZonedDateTime(). * * @return A new fluent assertion. */ public FluentZonedDateTimeAssertion assertZonedDateTime() { return new FluentResponseHeaderAssertion<>(this, this).asZonedDateTime(); } /** * Returns the response that created this object. * * @return The response that created this object. */ public RestResponse response() { return response; } //------------------------------------------------------------------------------------------------------------------ // Header passthrough methods. //------------------------------------------------------------------------------------------------------------------ /** * Parses the value. * * @return An array of {@link HeaderElement} entries, may be empty, but is never null. * @throws org.apache.http.ParseException In case of a parsing error. */ @Override /* Header */ public HeaderElement[] getElements() throws org.apache.http.ParseException { return elements; } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy