1 /* 2 * ==================================================================== 3 * Licensed to the Apache Software Foundation (ASF) under one 4 * or more contributor license agreements. See the NOTICE file 5 * distributed with this work for additional information 6 * regarding copyright ownership. The ASF licenses this file 7 * to you under the Apache License, Version 2.0 (the 8 * "License"); you may not use this file except in compliance 9 * with the License. You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, 14 * software distributed under the License is distributed on an 15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 * KIND, either express or implied. See the License for the 17 * specific language governing permissions and limitations 18 * under the License. 19 * ==================================================================== 20 * 21 * This software consists of voluntary contributions made by many 22 * individuals on behalf of the Apache Software Foundation. For more 23 * information on the Apache Software Foundation, please see 24 * <http://www.apache.org/>. 25 * 26 */ 27 28 package org.apache.hc.core5.http.io.entity; 29 30 import java.io.IOException; 31 import java.io.InputStream; 32 import java.io.OutputStream; 33 import java.util.Collections; 34 import java.util.List; 35 import java.util.Objects; 36 import java.util.Set; 37 38 import org.apache.hc.core5.function.Supplier; 39 import org.apache.hc.core5.http.ContentType; 40 import org.apache.hc.core5.http.Header; 41 import org.apache.hc.core5.http.HttpEntity; 42 import org.apache.hc.core5.util.Args; 43 44 /** 45 * Abstract base class for mutable entities. Provides the commonly used attributes for streamed and 46 * self-contained implementations. 47 * <p> 48 * This class contains immutable attributes but subclasses may contain additional immutable or mutable attributes. 49 * </p> 50 * 51 * @since 4.0 52 */ 53 public abstract class AbstractHttpEntity implements HttpEntity { 54 55 static final int OUTPUT_BUFFER_SIZE = 4096; 56 57 private final String contentType; 58 private final String contentEncoding; 59 private final boolean chunked; 60 61 /** 62 * Constructs a new instance with the given attributes kept as immutable. 63 * 64 * @param contentType The content-type string, may be null. 65 * @param contentEncoding The content encoding string, may be null. 66 * @param chunked Whether this entity should be chunked. 67 */ 68 protected AbstractHttpEntity(final String contentType, final String contentEncoding, final boolean chunked) { 69 this.contentType = contentType; 70 this.contentEncoding = contentEncoding; 71 this.chunked = chunked; 72 } 73 74 /** 75 * Constructs a new instance with the given attributes kept as immutable. 76 * 77 * @param contentType The content-type, may be null. 78 * @param contentEncoding The content encoding string, may be null. 79 * @param chunked Whether this entity should be chunked. 80 */ 81 protected AbstractHttpEntity(final ContentType contentType, final String contentEncoding, final boolean chunked) { 82 this.contentType = Objects.toString(contentType, null); 83 this.contentEncoding = contentEncoding; 84 this.chunked = chunked; 85 } 86 87 /** 88 * Constructs a new instance with the given attributes kept as immutable. 89 * <p> 90 * The new instance: 91 * </p> 92 * <ul> 93 * <li>is not chunked.</li> 94 * </ul> 95 * 96 * @param contentType The content-type string, may be null. 97 * @param contentEncoding The content encoding string, may be null. 98 */ 99 protected AbstractHttpEntity(final String contentType, final String contentEncoding) { 100 this(contentType, contentEncoding, false); 101 } 102 103 /** 104 * Constructs a new instance with the given attributes kept as immutable. 105 * <p> 106 * The new instance: 107 * </p> 108 * <ul> 109 * <li>is not chunked.</li> 110 * </ul> 111 * 112 * @param contentType The content-type, may be null. 113 * @param contentEncoding The content encoding string, may be null. 114 */ 115 protected AbstractHttpEntity(final ContentType contentType, final String contentEncoding) { 116 this(contentType, contentEncoding, false); 117 } 118 119 /** 120 * Writes an entity to an OutputStream. 121 * 122 * @param entity The entity to write, never null. 123 * @param outStream Where to write the entity, never null. 124 * @throws IOException if the entity cannot generate its content stream; also thrown if the output stream is closed. 125 * @throws UnsupportedOperationException if entity content cannot be represented as {@link java.io.InputStream}. 126 */ 127 public static void writeTo(final HttpEntity entity, final OutputStream outStream) throws IOException { 128 Args.notNull(entity, "Entity"); 129 Args.notNull(outStream, "Output stream"); 130 try (final InputStream inStream = entity.getContent()) { 131 if (inStream != null) { 132 int count; 133 final byte[] tmp = new byte[OUTPUT_BUFFER_SIZE]; 134 while ((count = inStream.read(tmp)) != -1) { 135 outStream.write(tmp, 0, count); 136 } 137 } 138 } 139 } 140 141 /** 142 * Writes this entity to an OutputStream. 143 * 144 * @param outStream Where to write the entity, never null. 145 * @throws IOException if the entity cannot generate its content stream; also thrown if the output stream is closed. 146 * @throws UnsupportedOperationException if entity content cannot be represented as {@link java.io.InputStream}. 147 */ 148 @Override 149 public void writeTo(final OutputStream outStream) throws IOException { 150 writeTo(this, outStream); 151 } 152 153 @Override 154 public final String getContentType() { 155 return contentType; 156 } 157 158 @Override 159 public final String getContentEncoding() { 160 return contentEncoding; 161 } 162 163 /** 164 * {@inheritDoc} 165 * <p> 166 * This implementation always returns {@code false}. 167 * </p> 168 */ 169 @Override 170 public final boolean isChunked() { 171 return chunked; 172 } 173 174 /** 175 * {@inheritDoc} 176 * <p> 177 * This implementation always returns {@code false}. 178 * </p> 179 */ 180 @Override 181 public boolean isRepeatable() { 182 return false; 183 } 184 185 /** 186 * {@inheritDoc} 187 * <p> 188 * This implementation always returns {@code null}. 189 * </p> 190 */ 191 @Override 192 public Supplier<List<? extends Header>> getTrailers() { 193 return null; 194 } 195 196 /** 197 * {@inheritDoc} 198 * <p> 199 * This implementation always returns an immutable empty set. 200 * </p> 201 */ 202 @Override 203 public Set<String> getTrailerNames() { 204 return Collections.emptySet(); 205 } 206 207 @Override 208 public String toString() { 209 final StringBuilder sb = new StringBuilder(); 210 sb.append("[Entity-Class: "); 211 sb.append(getClass().getSimpleName()); 212 sb.append(", Content-Type: "); 213 sb.append(contentType); 214 sb.append(", Content-Encoding: "); 215 sb.append(contentEncoding); 216 sb.append(", chunked: "); 217 sb.append(chunked); 218 sb.append(']'); 219 return sb.toString(); 220 } 221 222 }