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

org.glassfish.jersey.message.internal.InboundMessageContext Maven / Gradle / Ivy

Go to download

A bundle project producing JAX-RS RI bundles. The primary artifact is an "all-in-one" OSGi-fied JAX-RS RI bundle (jaxrs-ri.jar). Attached to that are two compressed JAX-RS RI archives. The first archive (jaxrs-ri.zip) consists of binary RI bits and contains the API jar (under "api" directory), RI libraries (under "lib" directory) as well as all external RI dependencies (under "ext" directory). The secondary archive (jaxrs-ri-src.zip) contains buildable JAX-RS RI source bundle and contains the API jar (under "api" directory), RI sources (under "src" directory) as well as all external RI dependencies (under "ext" directory). The second archive also contains "build.xml" ANT script that builds the RI sources. To build the JAX-RS RI simply unzip the archive, cd to the created jaxrs-ri directory and invoke "ant" from the command line.

There is a newer version: 3.1.6
Show newest version
/*
 * Copyright (c) 2012, 2020 Oracle and/or its affiliates. All rights reserved.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License v. 2.0, which is available at
 * http://www.eclipse.org/legal/epl-2.0.
 *
 * This Source Code may also be made available under the following Secondary
 * Licenses when the conditions for such availability set forth in the
 * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
 * version 2 with the GNU Classpath Exception, which is available at
 * https://www.gnu.org/software/classpath/license.html.
 *
 * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
 */

package org.glassfish.jersey.message.internal;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.Closeable;
import java.io.IOException;
import java.io.InputStream;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
import java.net.URI;
import java.text.ParseException;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.function.Function;

import jakarta.ws.rs.ProcessingException;
import jakarta.ws.rs.core.Configuration;
import jakarta.ws.rs.core.Cookie;
import jakarta.ws.rs.core.EntityTag;
import jakarta.ws.rs.core.HttpHeaders;
import jakarta.ws.rs.core.Link;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.MultivaluedMap;
import jakarta.ws.rs.core.NewCookie;
import jakarta.ws.rs.ext.ReaderInterceptor;

import javax.xml.transform.Source;

import org.glassfish.jersey.internal.LocalizationMessages;
import org.glassfish.jersey.internal.PropertiesDelegate;
import org.glassfish.jersey.internal.RuntimeDelegateDecorator;
import org.glassfish.jersey.message.MessageBodyWorkers;

/**
 * Base inbound message context implementation.
 *
 * @author Marek Potociar
 */
public abstract class InboundMessageContext {

    private static final InputStream EMPTY = new InputStream() {

        @Override
        public int read() throws IOException {
            return -1;
        }

        @Override
        public void mark(int readlimit) {
            // no-op
        }

        @Override
        public void reset() throws IOException {
            // no-op
        }

        @Override
        public boolean markSupported() {
            return true;
        }
    };
    private static final Annotation[] EMPTY_ANNOTATIONS = new Annotation[0];
    private static final List WILDCARD_ACCEPTABLE_TYPE_SINGLETON_LIST =
            Collections.singletonList(MediaTypes.WILDCARD_ACCEPTABLE_TYPE);

    private final MultivaluedMap headers;
    private final EntityContent entityContent;
    private final boolean translateNce;
    private MessageBodyWorkers workers;
    private final Configuration configuration;

    /**
     * Input stream and its state. State is represented by the {@link Type Type enum} and
     * is used to control the execution of interceptors.
     */
    private static class EntityContent extends EntityInputStream {

        private boolean buffered;

        EntityContent() {
            super(EMPTY);
        }

        void setContent(InputStream content, boolean buffered) {
            this.buffered = buffered;
            setWrappedStream(content);
        }

        boolean hasContent() {
            return getWrappedStream() != EMPTY;
        }

        boolean isBuffered() {
            return buffered;
        }

        @Override
        public void close() {
            close(false);
        }

        void close(boolean force) {
            if (buffered && !force) {
                return;
            }
            try {
                super.close();
            } finally {
                buffered = false;
                setWrappedStream(null);
            }
        }
    }

    /**
     * Create new inbound message context.
     *
     * @param configuration the related client/server side {@link Configuration}
     */
    public InboundMessageContext(Configuration configuration) {
        this(configuration, false);
    }

    /**
     * Create new inbound message context.
     *
     * @param configuration the related client/server side {@link Configuration}. If {@code null},
     *                      the default behaviour is expected.
     * @param translateNce  if {@code true}, the {@link jakarta.ws.rs.core.NoContentException} thrown by a
     *                      selected message body reader will be translated into a {@link jakarta.ws.rs.BadRequestException}
     *                      as required by JAX-RS specification on the server side.
     */
    public InboundMessageContext(Configuration configuration, boolean translateNce) {
        this.headers = HeaderUtils.createInbound();
        this.entityContent = new EntityContent();
        this.translateNce = translateNce;
        this.configuration = configuration;
    }

    /**
     * Create new inbound message context.
     * @see #InboundMessageContext(Configuration)
     */
    @Deprecated
    public InboundMessageContext() {
        this((Configuration) null);
    }

    /**
     * Create new inbound message context.
     *
     * @param translateNce  if {@code true}, the {@link jakarta.ws.rs.core.NoContentException} thrown by a
     *                      selected message body reader will be translated into a {@link jakarta.ws.rs.BadRequestException}
     *                      as required by JAX-RS specification on the server side.     *
     * @see #InboundMessageContext(Configuration)
     */
    @Deprecated
    public InboundMessageContext(boolean translateNce) {
        this((Configuration) null, translateNce);
    }

    // Message headers

    /**
     * Add a new header value.
     *
     * @param name  header name.
     * @param value header value.
     * @return updated context.
     */
    public InboundMessageContext header(String name, Object value) {
        getHeaders().add(name, HeaderUtils.asString(value, configuration));
        return this;
    }

    /**
     * Add new header values.
     *
     * @param name   header name.
     * @param values header values.
     * @return updated context.
     */
    public InboundMessageContext headers(String name, Object... values) {
        this.getHeaders().addAll(name, HeaderUtils.asStringList(Arrays.asList(values), configuration));
        return this;
    }

    /**
     * Add new header values.
     *
     * @param name   header name.
     * @param values header values.
     * @return updated context.
     */
    public InboundMessageContext headers(String name, Iterable values) {
        this.getHeaders().addAll(name, iterableToList(values));
        return this;
    }

    /**
     * Add new headers.
     *
     * @param newHeaders new headers.
     * @return updated context.
     */
    public InboundMessageContext headers(MultivaluedMap newHeaders) {
        for (Map.Entry> header : newHeaders.entrySet()) {
            headers.addAll(header.getKey(), header.getValue());
        }
        return this;
    }

    /**
     * Add new headers.
     *
     * @param newHeaders new headers.
     * @return updated context.
     */
    public InboundMessageContext headers(Map> newHeaders) {
        for (Map.Entry> header : newHeaders.entrySet()) {
            headers.addAll(header.getKey(), header.getValue());
        }
        return this;
    }

    /**
     * Remove a header.
     *
     * @param name header name.
     * @return updated context.
     */
    public InboundMessageContext remove(String name) {
        this.getHeaders().remove(name);
        return this;
    }

    private List iterableToList(final Iterable values) {
        final LinkedList linkedList = new LinkedList();

        for (Object element : values) {
            linkedList.add(HeaderUtils.asString(element, configuration));
        }

        return linkedList;
    }

    /**
     * Get a message header as a single string value.
     * 

* Each single header value is converted to String using a * {@link jakarta.ws.rs.ext.RuntimeDelegate.HeaderDelegate} if one is available * via {@link jakarta.ws.rs.ext.RuntimeDelegate#createHeaderDelegate(java.lang.Class)} * for the header value class or using its {@code toString} method if a header * delegate is not available. * * @param name the message header. * @return the message header value. If the message header is not present then * {@code null} is returned. If the message header is present but has no * value then the empty string is returned. If the message header is present * more than once then the values of joined together and separated by a ',' * character. */ public String getHeaderString(String name) { List values = this.headers.get(name); if (values == null) { return null; } if (values.isEmpty()) { return ""; } final Iterator valuesIterator = values.iterator(); StringBuilder buffer = new StringBuilder(valuesIterator.next()); while (valuesIterator.hasNext()) { buffer.append(',').append(valuesIterator.next()); } return buffer.toString(); } /** * Get a single typed header value. * * @param name header name. * @param converter from string conversion function. Is expected to throw {@link ProcessingException} * if conversion fails. * @param convertNull if {@code true} this method calls the provided converter even for {@code null}. Otherwise this * method returns the {@code null} without calling the converter. * @return value of the header, or (possibly converted) {@code null} if not present. */ private T singleHeader(String name, Function converter, boolean convertNull) { final List values = this.headers.get(name); if (values == null || values.isEmpty()) { return convertNull ? converter.apply(null) : null; } if (values.size() > 1) { throw new HeaderValueException(LocalizationMessages.TOO_MANY_HEADER_VALUES(name, values.toString()), HeaderValueException.Context.INBOUND); } Object value = values.get(0); if (value == null) { return convertNull ? converter.apply(null) : null; } try { return converter.apply(HeaderUtils.asString(value, configuration)); } catch (ProcessingException ex) { throw exception(name, value, ex); } } private static HeaderValueException exception(final String headerName, Object headerValue, Exception e) { return new HeaderValueException(LocalizationMessages.UNABLE_TO_PARSE_HEADER_VALUE(headerName, headerValue), e, HeaderValueException.Context.INBOUND); } /** * Get the mutable message headers multivalued map. * * @return mutable multivalued map of message headers. */ public MultivaluedMap getHeaders() { return this.headers; } /** * Get message date. * * @return the message date, otherwise {@code null} if not present. */ public Date getDate() { return singleHeader(HttpHeaders.DATE, new Function() { @Override public Date apply(String input) { try { return HttpHeaderReader.readDate(input); } catch (ParseException ex) { throw new ProcessingException(ex); } } }, false); } /** * Get If-Match header. * * @return the If-Match header value, otherwise {@code null} if not present. */ public Set getIfMatch() { final String ifMatch = getHeaderString(HttpHeaders.IF_MATCH); if (ifMatch == null || ifMatch.isEmpty()) { return null; } try { return HttpHeaderReader.readMatchingEntityTag(ifMatch); } catch (java.text.ParseException e) { throw exception(HttpHeaders.IF_MATCH, ifMatch, e); } } /** * Get If-None-Match header. * * @return the If-None-Match header value, otherwise {@code null} if not present. */ public Set getIfNoneMatch() { final String ifNoneMatch = getHeaderString(HttpHeaders.IF_NONE_MATCH); if (ifNoneMatch == null || ifNoneMatch.isEmpty()) { return null; } try { return HttpHeaderReader.readMatchingEntityTag(ifNoneMatch); } catch (java.text.ParseException e) { throw exception(HttpHeaders.IF_NONE_MATCH, ifNoneMatch, e); } } /** * Get the language of the entity. * * @return the language of the entity or {@code null} if not specified. */ public Locale getLanguage() { return singleHeader(HttpHeaders.CONTENT_LANGUAGE, new Function() { @Override public Locale apply(String input) { try { return new LanguageTag(input).getAsLocale(); } catch (ParseException e) { throw new ProcessingException(e); } } }, false); } /** * Get Content-Length value. * * @return Content-Length as integer if present and valid number. In other cases returns -1. */ public int getLength() { return singleHeader(HttpHeaders.CONTENT_LENGTH, new Function() { @Override public Integer apply(String input) { try { return (input != null && !input.isEmpty()) ? Integer.parseInt(input) : -1; } catch (NumberFormatException ex) { throw new ProcessingException(ex); } } }, true); } /** * Get the media type of the entity. * * @return the media type or {@code null} if not specified (e.g. there's no * message entity). */ public MediaType getMediaType() { return singleHeader(HttpHeaders.CONTENT_TYPE, new Function() { @Override public MediaType apply(String input) { try { return RuntimeDelegateDecorator.configured(configuration) .createHeaderDelegate(MediaType.class) .fromString(input); } catch (IllegalArgumentException iae) { throw new ProcessingException(iae); } } }, false); } /** * Get a list of media types that are acceptable for a request. * * @return a read-only list of requested response media types sorted according * to their q-value, with highest preference first. */ public List getQualifiedAcceptableMediaTypes() { final String value = getHeaderString(HttpHeaders.ACCEPT); if (value == null || value.isEmpty()) { return WILDCARD_ACCEPTABLE_TYPE_SINGLETON_LIST; } try { return Collections.unmodifiableList(HttpHeaderReader.readAcceptMediaType(value)); } catch (ParseException e) { throw exception(HttpHeaders.ACCEPT, value, e); } } /** * Get a list of languages that are acceptable for the message. * * @return a read-only list of acceptable languages sorted according * to their q-value, with highest preference first. */ public List getQualifiedAcceptableLanguages() { final String value = getHeaderString(HttpHeaders.ACCEPT_LANGUAGE); if (value == null || value.isEmpty()) { return Collections.singletonList(new AcceptableLanguageTag("*", null)); } try { return Collections.unmodifiableList(HttpHeaderReader.readAcceptLanguage(value)); } catch (ParseException e) { throw exception(HttpHeaders.ACCEPT_LANGUAGE, value, e); } } /** * Get the list of language tag from the "Accept-Charset" of an HTTP request. * * @return The list of AcceptableToken. This list * is ordered with the highest quality acceptable charset occurring first. */ public List getQualifiedAcceptCharset() { final String acceptCharset = getHeaderString(HttpHeaders.ACCEPT_CHARSET); try { if (acceptCharset == null || acceptCharset.isEmpty()) { return Collections.singletonList(new AcceptableToken("*")); } return HttpHeaderReader.readAcceptToken(acceptCharset); } catch (java.text.ParseException e) { throw exception(HttpHeaders.ACCEPT_CHARSET, acceptCharset, e); } } /** * Get the list of language tag from the "Accept-Charset" of an HTTP request. * * @return The list of AcceptableToken. This list * is ordered with the highest quality acceptable charset occurring first. */ public List getQualifiedAcceptEncoding() { final String acceptEncoding = getHeaderString(HttpHeaders.ACCEPT_ENCODING); try { if (acceptEncoding == null || acceptEncoding.isEmpty()) { return Collections.singletonList(new AcceptableToken("*")); } return HttpHeaderReader.readAcceptToken(acceptEncoding); } catch (java.text.ParseException e) { throw exception("Accept-Encoding", acceptEncoding, e); } } /** * Get any cookies that accompanied the request. * * @return a read-only map of cookie name (String) to {@link jakarta.ws.rs.core.Cookie}. */ public Map getRequestCookies() { List cookies = this.headers.get(HttpHeaders.COOKIE); if (cookies == null || cookies.isEmpty()) { return Collections.emptyMap(); } Map result = new HashMap(); for (String cookie : cookies) { if (cookie != null) { result.putAll(HttpHeaderReader.readCookies(cookie)); } } return result; } /** * Get the allowed HTTP methods from the Allow HTTP header. * * @return the allowed HTTP methods, all methods will returned as upper case * strings. */ public Set getAllowedMethods() { final String allowed = getHeaderString(HttpHeaders.ALLOW); if (allowed == null || allowed.isEmpty()) { return Collections.emptySet(); } try { return new HashSet(HttpHeaderReader.readStringList(allowed.toUpperCase(Locale.ROOT))); } catch (java.text.ParseException e) { throw exception(HttpHeaders.ALLOW, allowed, e); } } /** * Get any new cookies set on the response message. * * @return a read-only map of cookie name (String) to a {@link jakarta.ws.rs.core.NewCookie new cookie}. */ public Map getResponseCookies() { List cookies = this.headers.get(HttpHeaders.SET_COOKIE); if (cookies == null || cookies.isEmpty()) { return Collections.emptyMap(); } Map result = new HashMap(); for (String cookie : cookies) { if (cookie != null) { NewCookie newCookie = HttpHeaderReader.readNewCookie(cookie); String cookieName = newCookie.getName(); if (result.containsKey(cookieName)) { result.put(cookieName, HeaderUtils.getPreferredCookie(result.get(cookieName), newCookie)); } else { result.put(cookieName, newCookie); } } } return result; } /** * Get the entity tag. * * @return the entity tag, otherwise {@code null} if not present. */ public EntityTag getEntityTag() { return singleHeader(HttpHeaders.ETAG, new Function() { @Override public EntityTag apply(String value) { return EntityTag.valueOf(value); } }, false); } /** * Get the last modified date. * * @return the last modified date, otherwise {@code null} if not present. */ public Date getLastModified() { return singleHeader(HttpHeaders.LAST_MODIFIED, new Function() { @Override public Date apply(String input) { try { return HttpHeaderReader.readDate(input); } catch (ParseException e) { throw new ProcessingException(e); } } }, false); } /** * Get the location. * * @return the location URI, otherwise {@code null} if not present. */ public URI getLocation() { return singleHeader(HttpHeaders.LOCATION, new Function() { @Override public URI apply(String value) { try { return URI.create(value); } catch (IllegalArgumentException ex) { throw new ProcessingException(ex); } } }, false); } /** * Get the links attached to the message as header. * * @return links, may return empty {@link java.util.Set} if no links are present. Never * returns {@code null}. */ public Set getLinks() { List links = this.headers.get(HttpHeaders.LINK); if (links == null || links.isEmpty()) { return Collections.emptySet(); } try { Set result = new HashSet(links.size()); StringBuilder linkString; for (String link : links) { linkString = new StringBuilder(); StringTokenizer st = new StringTokenizer(link, "<>,", true); boolean linkOpen = false; while (st.hasMoreTokens()) { String n = st.nextToken(); if (n.equals("<")) { linkOpen = true; } else if (n.equals(">")) { linkOpen = false; } else if (!linkOpen && n.equals(",")) { result.add(Link.valueOf(linkString.toString().trim())); linkString = new StringBuilder(); continue; // don't add the "," } linkString.append(n); } if (linkString.length() > 0) { result.add(Link.valueOf(linkString.toString().trim())); } } return result; } catch (IllegalArgumentException e) { throw exception(HttpHeaders.LINK, links, e); } } /** * Check if link for relation exists. * * @param relation link relation. * @return {@code true} if the for the relation link exists, {@code false} * otherwise. */ public boolean hasLink(String relation) { for (Link link : getLinks()) { List relations = LinkProvider.getLinkRelations(link.getRel()); if (relations != null && relations.contains(relation)) { return true; } } return false; } /** * Get the link for the relation. * * @param relation link relation. * @return the link for the relation, otherwise {@code null} if not present. */ public Link getLink(String relation) { for (Link link : getLinks()) { List relations = LinkProvider.getLinkRelations(link.getRel()); if (relations != null && relations.contains(relation)) { return link; } } return null; } /** * Convenience method that returns a {@link jakarta.ws.rs.core.Link.Builder Link.Builder} * for the relation. * * @param relation link relation. * @return the link builder for the relation, otherwise {@code null} if not * present. */ public Link.Builder getLinkBuilder(String relation) { Link link = getLink(relation); if (link == null) { return null; } return Link.fromLink(link); } // Message entity /** * Get context message body workers. * * @return context message body workers. */ public MessageBodyWorkers getWorkers() { return workers; } /** * Set context message body workers. * * @param workers context message body workers. */ public void setWorkers(MessageBodyWorkers workers) { this.workers = workers; } /** * Check if there is a non-empty entity input stream is available in the * message. *

* The method returns {@code true} if the entity is present, returns * {@code false} otherwise. * * @return {@code true} if there is an entity present in the message, * {@code false} otherwise. */ public boolean hasEntity() { entityContent.ensureNotClosed(); try { return !entityContent.isEmpty(); } catch (IllegalStateException ex) { // input stream has been closed. return false; } } /** * Get the entity input stream. * * @return entity input stream. */ public InputStream getEntityStream() { entityContent.ensureNotClosed(); return entityContent.getWrappedStream(); } /** * Set a new entity input stream. * * @param input new entity input stream. */ public void setEntityStream(InputStream input) { this.entityContent.setContent(input, false); } /** * Read entity from a context entity input stream. * * @param entity Java object type. * @param rawType raw Java entity type. * @param propertiesDelegate request-scoped properties delegate. * @return entity read from a context entity input stream. */ public T readEntity(Class rawType, PropertiesDelegate propertiesDelegate) { return readEntity(rawType, rawType, EMPTY_ANNOTATIONS, propertiesDelegate); } /** * Read entity from a context entity input stream. * * @param entity Java object type. * @param rawType raw Java entity type. * @param annotations entity annotations. * @param propertiesDelegate request-scoped properties delegate. * @return entity read from a context entity input stream. */ public T readEntity(Class rawType, Annotation[] annotations, PropertiesDelegate propertiesDelegate) { return readEntity(rawType, rawType, annotations, propertiesDelegate); } /** * Read entity from a context entity input stream. * * @param entity Java object type. * @param rawType raw Java entity type. * @param type generic Java entity type. * @param propertiesDelegate request-scoped properties delegate. * @return entity read from a context entity input stream. */ public T readEntity(Class rawType, Type type, PropertiesDelegate propertiesDelegate) { return readEntity(rawType, type, EMPTY_ANNOTATIONS, propertiesDelegate); } /** * Read entity from a context entity input stream. * * @param entity Java object type. * @param rawType raw Java entity type. * @param type generic Java entity type. * @param annotations entity annotations. * @param propertiesDelegate request-scoped properties delegate. * @return entity read from a context entity input stream. */ @SuppressWarnings("unchecked") public T readEntity(Class rawType, Type type, Annotation[] annotations, PropertiesDelegate propertiesDelegate) { final boolean buffered = entityContent.isBuffered(); if (buffered) { entityContent.reset(); } entityContent.ensureNotClosed(); // TODO: revise if we need to re-introduce the check for performance reasons or once non-blocking I/O is supported. // The code has been commended out because in case of streaming input (e.g. SSE) the call might block until a first // byte is available, which would make e.g. the SSE EventSource construction or EventSource.open() method to block // until a first event is received, which is undesirable. // // if (entityContent.isEmpty()) { // return null; // } if (workers == null) { return null; } MediaType mediaType = getMediaType(); mediaType = mediaType == null ? MediaType.APPLICATION_OCTET_STREAM_TYPE : mediaType; boolean shouldClose = !buffered; try { T t = (T) workers.readFrom( rawType, type, annotations, mediaType, headers, propertiesDelegate, entityContent.getWrappedStream(), entityContent.hasContent() ? getReaderInterceptors() : Collections.emptyList(), translateNce); shouldClose = shouldClose && !(t instanceof Closeable) && !(t instanceof Source); return t; } catch (IOException ex) { throw new ProcessingException(LocalizationMessages.ERROR_READING_ENTITY_FROM_INPUT_STREAM(), ex); } finally { if (shouldClose) { // Workaround for JRFCAF-1344: the underlying stream close() implementation may be thread-unsafe // and as such the close() may result in an IOException at the socket input stream level, // if the close() gets called at once from multiple threads somehow. // We want to ignore these exceptions in the readEntity/bufferEntity operations though. ReaderWriter.safelyClose(entityContent); } } } /** * Buffer the entity stream (if not empty). * * @return {@code true} if the entity input stream was successfully buffered. * @throws jakarta.ws.rs.ProcessingException in case of an IO error. */ public boolean bufferEntity() throws ProcessingException { entityContent.ensureNotClosed(); try { if (entityContent.isBuffered() || !entityContent.hasContent()) { return true; } final InputStream entityStream = entityContent.getWrappedStream(); ByteArrayOutputStream baos = new ByteArrayOutputStream(); try { ReaderWriter.writeTo(entityStream, baos); } finally { // Workaround for JRFCAF-1344: the underlying stream close() implementation may be thread-unsafe // and as such the close() may result in an IOException at the socket input stream level, // if the close() gets called at once from multiple threads somehow. // We want to ignore these exceptions in the readEntity/bufferEntity operations though. ReaderWriter.safelyClose(entityStream); } entityContent.setContent(new ByteArrayInputStream(baos.toByteArray()), true); return true; } catch (IOException ex) { throw new ProcessingException(LocalizationMessages.MESSAGE_CONTENT_BUFFERING_FAILED(), ex); } } /** * Closes the underlying content stream. */ public void close() { entityContent.close(true); } /** * Get reader interceptors bound to this context. *

* Interceptors will be used when one of the {@code readEntity} methods is invoked. *

* * @return reader interceptors bound to this context. */ protected abstract Iterable getReaderInterceptors(); /** * The related client/server side {@link Configuration}. Can be {@code null}. * @return {@link Configuration} the configuration */ public Configuration getConfiguration() { return configuration; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy