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

com.wl4g.infra.common.remoting.parse.ResourceHttpMessageParser Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2017 ~ 2025 the original author or authors. James Wong 
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.wl4g.infra.common.remoting.parse;

import static java.lang.String.format;
import static java.util.Objects.isNull;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;

import javax.annotation.Nullable;
import com.wl4g.infra.common.io.ByteStreamUtils;
import com.wl4g.infra.common.remoting.standard.HttpMediaType;
import com.wl4g.infra.common.remoting.standard.MediaTypeFactory;
import com.wl4g.infra.common.resource.ByteArrayStreamResource;
import com.wl4g.infra.common.resource.InputStreamResource;
import com.wl4g.infra.common.resource.StreamResource;

/**
 * Implementation of {@link HttpMessageConverter} that can read/write
 * {@link Resource Resources} and supports byte range requests.
 *
 * 

* By default, this converter can read all media types. The * {@link MediaTypeFactory} is used to determine the {@code Content-Type} of * written resources. */ public class ResourceHttpMessageParser extends AbstractHttpMessageParser { private final boolean supportsReadStreaming; /** * Create a new instance of the {@code ResourceHttpMessageConverter} that * supports read streaming, i.e. can convert an {@code HttpInputMessage} to * {@code InputStreamResource}. */ public ResourceHttpMessageParser() { super(HttpMediaType.ALL); this.supportsReadStreaming = true; } /** * Create a new instance of the {@code ResourceHttpMessageConverter}. * * @param supportsReadStreaming * whether the converter should support read streaming, i.e. * convert to {@code InputStreamResource} * @since 5.0 */ public ResourceHttpMessageParser(boolean supportsReadStreaming) { super(HttpMediaType.ALL); this.supportsReadStreaming = supportsReadStreaming; } @Override protected boolean supports(Class clazz) { return StreamResource.class.isAssignableFrom(clazz); } @Override protected StreamResource readInternal(Class clazz, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException { if (this.supportsReadStreaming && InputStreamResource.class == clazz) { return new InputStreamResource(inputMessage.getBody()) { @Override public String getFilename() { return inputMessage.getHeaders().getContentDisposition().getFilename(); } @Override public long contentLength() throws IOException { long length = inputMessage.getHeaders().getContentLength(); return (length != -1 ? length : super.contentLength()); } }; } else if (StreamResource.class == clazz || ByteArrayStreamResource.class.isAssignableFrom(clazz)) { InputStream in = inputMessage.getBody(); long bytes = in.available(); if (bytes >= DEFAULT_MEMORY_FILE_BYTES_LIMIT) { throw new IOException(format( "This file object is too large, about %s bytes. It is recommended to use the request with accept ranges header to support interrupt download", bytes)); } byte[] body = ByteStreamUtils.copyToByteArray(in); return new ByteArrayStreamResource(body) { @Override @Nullable public String getFilename() { return inputMessage.getHeaders().getContentDisposition().getFilename(); } }; } else { throw new HttpMessageNotReadableException("Unsupported resource class: " + clazz); } } @Override protected HttpMediaType getDefaultContentType(StreamResource resource) { return MediaTypeFactory.getMediaType(resource).filter(m -> !isNull(m)).orElse(HttpMediaType.APPLICATION_OCTET_STREAM); } @Override protected Long getContentLength(StreamResource resource, @Nullable HttpMediaType contentType) throws IOException { // Don't try to determine contentLength on InputStreamResource - cannot // be read afterwards... // Note: custom InputStreamResource subclasses could provide a // pre-calculated content length! if (InputStreamResource.class == resource.getClass()) { return null; } long contentLength = resource.contentLength(); return (contentLength < 0 ? null : contentLength); } @Override protected void writeInternal(StreamResource resource, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException { writeContent(resource, outputMessage); } protected void writeContent(StreamResource resource, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException { try { InputStream in = resource.getInputStream(); try { ByteStreamUtils.copy(in, outputMessage.getBody()); } catch (NullPointerException ex) { // ignore, see SPR-13620 } finally { try { in.close(); } catch (Throwable ex) { // ignore, see SPR-12999 } } } catch (FileNotFoundException ex) { // ignore, see SPR-12999 } } final public static long DEFAULT_MEMORY_FILE_BYTES_LIMIT = 1024 * 1024 * 10; }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy