001/* 002 * Copyright 2002-2015 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.core.io; 018 019import java.io.IOException; 020import java.io.InputStream; 021 022/** 023 * {@link Resource} implementation for a given {@link InputStream}. 024 * <p>Should only be used if no other specific {@code Resource} implementation 025 * is applicable. In particular, prefer {@link ByteArrayResource} or any of the 026 * file-based {@code Resource} implementations where possible. 027 * 028 * <p>In contrast to other {@code Resource} implementations, this is a descriptor 029 * for an <i>already opened</i> resource - therefore returning {@code true} from 030 * {@link #isOpen()}. Do not use an {@code InputStreamResource} if you need to 031 * keep the resource descriptor somewhere, or if you need to read from a stream 032 * multiple times. 033 * 034 * @author Juergen Hoeller 035 * @author Sam Brannen 036 * @since 28.12.2003 037 * @see ByteArrayResource 038 * @see ClassPathResource 039 * @see FileSystemResource 040 * @see UrlResource 041 */ 042public class InputStreamResource extends AbstractResource { 043 044 private final InputStream inputStream; 045 046 private final String description; 047 048 private boolean read = false; 049 050 051 /** 052 * Create a new InputStreamResource. 053 * @param inputStream the InputStream to use 054 */ 055 public InputStreamResource(InputStream inputStream) { 056 this(inputStream, "resource loaded through InputStream"); 057 } 058 059 /** 060 * Create a new InputStreamResource. 061 * @param inputStream the InputStream to use 062 * @param description where the InputStream comes from 063 */ 064 public InputStreamResource(InputStream inputStream, String description) { 065 if (inputStream == null) { 066 throw new IllegalArgumentException("InputStream must not be null"); 067 } 068 this.inputStream = inputStream; 069 this.description = (description != null ? description : ""); 070 } 071 072 073 /** 074 * This implementation always returns {@code true}. 075 */ 076 @Override 077 public boolean exists() { 078 return true; 079 } 080 081 /** 082 * This implementation always returns {@code true}. 083 */ 084 @Override 085 public boolean isOpen() { 086 return true; 087 } 088 089 /** 090 * This implementation throws IllegalStateException if attempting to 091 * read the underlying stream multiple times. 092 */ 093 @Override 094 public InputStream getInputStream() throws IOException, IllegalStateException { 095 if (this.read) { 096 throw new IllegalStateException("InputStream has already been read - " + 097 "do not use InputStreamResource if a stream needs to be read multiple times"); 098 } 099 this.read = true; 100 return this.inputStream; 101 } 102 103 /** 104 * This implementation returns a description that includes the passed-in 105 * description, if any. 106 */ 107 @Override 108 public String getDescription() { 109 return "InputStream resource [" + this.description + "]"; 110 } 111 112 113 /** 114 * This implementation compares the underlying InputStream. 115 */ 116 @Override 117 public boolean equals(Object obj) { 118 return (obj == this || 119 (obj instanceof InputStreamResource && ((InputStreamResource) obj).inputStream.equals(this.inputStream))); 120 } 121 122 /** 123 * This implementation returns the hash code of the underlying InputStream. 124 */ 125 @Override 126 public int hashCode() { 127 return this.inputStream.hashCode(); 128 } 129 130}