001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.juneau.http.entity; 018 019import static org.apache.juneau.commons.utils.AssertionUtils.*; 020import static org.apache.juneau.commons.utils.IoUtils.*; 021import static org.apache.juneau.commons.utils.Utils.*; 022 023import java.io.*; 024import java.nio.charset.*; 025import java.util.*; 026import java.util.function.*; 027 028import org.apache.juneau.http.header.*; 029 030/** 031 * A repeatable entity that obtains its content from a {@link File}. 032 * 033 * <h5 class='section'>See Also:</h5><ul> 034 * <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/JuneauRestCommonBasics">juneau-rest-common Basics</a> 035 * </ul> 036 */ 037@SuppressWarnings("resource") 038public class FileEntity extends BasicHttpEntity { 039 private byte[] byteCache; 040 private String stringCache; 041 042 /** 043 * Constructor. 044 */ 045 public FileEntity() {} 046 047 /** 048 * Constructor. 049 * 050 * @param contentType The entity content type. 051 * @param content The entity contents. 052 */ 053 public FileEntity(ContentType contentType, File content) { 054 super(contentType, content); 055 } 056 057 /** 058 * Copy constructor. 059 * 060 * @param copyFrom The bean being copied. 061 */ 062 protected FileEntity(FileEntity copyFrom) { 063 super(copyFrom); 064 } 065 066 @Override /* Overridden from AbstractHttpEntity */ 067 public byte[] asBytes() throws IOException { 068 if (isCached() && byteCache == null) 069 byteCache = readBytes(content(), getMaxLength()); 070 if (nn(byteCache)) 071 return byteCache; 072 return readBytes(content()); 073 } 074 075 @Override /* Overridden from AbstractHttpEntity */ 076 public String asString() throws IOException { 077 if (isCached() && stringCache == null) 078 stringCache = read(new InputStreamReader(new FileInputStream(content()), getCharset()), getMaxLength()); 079 if (nn(stringCache)) 080 return stringCache; 081 return read(new InputStreamReader(new FileInputStream(content()), getCharset()), getMaxLength()); 082 } 083 084 @Override 085 public FileEntity copy() { 086 return new FileEntity(this); 087 } 088 089 @Override /* Overridden from HttpEntity */ 090 public InputStream getContent() throws IOException { 091 if (isCached()) 092 return new ByteArrayInputStream(asBytes()); 093 return new FileInputStream(content()); 094 } 095 096 @Override /* Overridden from HttpEntity */ 097 public long getContentLength() { return content().length(); } 098 099 @Override /* Overridden from HttpEntity */ 100 public boolean isRepeatable() { return true; } 101 102 @Override /* Overridden from BasicHttpEntity */ 103 public FileEntity setCached() throws IOException { 104 super.setCached(); 105 return this; 106 } 107 108 @Override /* Overridden from BasicHttpEntity */ 109 public FileEntity setCharset(Charset value) { 110 super.setCharset(value); 111 return this; 112 } 113 114 @Override /* Overridden from BasicHttpEntity */ 115 public FileEntity setChunked() { 116 super.setChunked(); 117 return this; 118 } 119 120 @Override /* Overridden from BasicHttpEntity */ 121 public FileEntity setChunked(boolean value) { 122 super.setChunked(value); 123 return this; 124 } 125 126 @Override /* Overridden from BasicHttpEntity */ 127 public FileEntity setContent(Object value) { 128 super.setContent(value); 129 return this; 130 } 131 132 @Override /* Overridden from BasicHttpEntity */ 133 public FileEntity setContent(Supplier<?> value) { 134 super.setContent(value); 135 return this; 136 } 137 138 @Override /* Overridden from BasicHttpEntity */ 139 public FileEntity setContentEncoding(ContentEncoding value) { 140 super.setContentEncoding(value); 141 return this; 142 } 143 144 @Override /* Overridden from BasicHttpEntity */ 145 public FileEntity setContentEncoding(String value) { 146 super.setContentEncoding(value); 147 return this; 148 } 149 150 @Override /* Overridden from BasicHttpEntity */ 151 public FileEntity setContentLength(long value) { 152 super.setContentLength(value); 153 return this; 154 } 155 156 @Override /* Overridden from BasicHttpEntity */ 157 public FileEntity setContentType(ContentType value) { 158 super.setContentType(value); 159 return this; 160 } 161 162 @Override /* Overridden from BasicHttpEntity */ 163 public FileEntity setContentType(String value) { 164 super.setContentType(value); 165 return this; 166 } 167 168 @Override /* Overridden from BasicHttpEntity */ 169 public FileEntity setMaxLength(int value) { 170 super.setMaxLength(value); 171 return this; 172 } 173 174 @Override /* Overridden from BasicHttpEntity */ 175 public FileEntity setUnmodifiable() { 176 super.setUnmodifiable(); 177 return this; 178 } 179 180 @Override /* Overridden from HttpEntity */ 181 public void writeTo(OutputStream out) throws IOException { 182 assertArgNotNull("out", out); 183 184 if (isCached()) { 185 out.write(asBytes()); 186 } else { 187 try (var is = getContent()) { 188 pipe(is, out, getMaxLength()); 189 } 190 } 191 } 192 193 private File content() { 194 var f = contentOrElse((File)null); 195 Objects.requireNonNull(f, "File"); 196 if (! f.exists()) 197 throw new IllegalStateException("File " + f.getAbsolutePath() + " does not exist."); 198 if (! f.canRead()) 199 throw new IllegalStateException("File " + f.getAbsolutePath() + " is not readable."); 200 return f; 201 } 202}