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.function.*;
026
027import org.apache.juneau.commons.io.*;
028import org.apache.juneau.http.header.*;
029
030/**
031 * A self contained, repeatable entity that obtains its content from a {@link String}.
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 StringEntity extends BasicHttpEntity {
039   private static final String EMPTY = "";
040   private byte[] byteCache;
041
042   /**
043    * Constructor.
044    */
045   public StringEntity() {}
046
047   /**
048    * Constructor.
049    *
050    * @param contentType The entity content type.
051    * @param content The entity contents.
052    */
053   public StringEntity(ContentType contentType, String content) {
054      super(contentType, content);
055   }
056
057   /**
058    * Copy constructor.
059    *
060    * @param copyFrom The bean being copied.
061    */
062   protected StringEntity(StringEntity copyFrom) {
063      super(copyFrom);
064   }
065
066   @Override /* Overridden from AbstractHttpEntity */
067   public byte[] asBytes() throws IOException {
068      if (isCached() && byteCache == null)
069         byteCache = content().getBytes(getCharset());
070      if (nn(byteCache))
071         return byteCache;
072      return content().getBytes(getCharset());
073   }
074
075   @Override /* Overridden from AbstractHttpEntity */
076   public String asString() throws IOException {
077      return content();
078   }
079
080   @Override
081   public StringEntity copy() {
082      return new StringEntity(this);
083   }
084
085   @Override /* Overridden from HttpEntity */
086   public InputStream getContent() throws IOException {
087      if (isCached())
088         return new ByteArrayInputStream(asBytes());
089      return new ReaderInputStream(new StringReader(content()), getCharset());
090   }
091
092   @Override /* Overridden from HttpEntity */
093   public long getContentLength() {
094      if (isCached())
095         return asSafeBytes().length;
096      long l = super.getContentLength();
097      if (l != -1 || isSupplied())
098         return l;
099      String s = content();
100      if (getCharset() == UTF8)
101         for (var i = 0; i < s.length(); i++)
102            if (s.charAt(i) > 127)
103               return -1;
104      return s.length();
105   }
106
107   @Override /* Overridden from HttpEntity */
108   public boolean isRepeatable() { return true; }
109
110   @Override /* Overridden from HttpEntity */
111   public boolean isStreaming() { return false; }
112
113   @Override /* Overridden from BasicHttpEntity */
114   public StringEntity setCached() throws IOException {
115      super.setCached();
116      return this;
117   }
118
119   @Override /* Overridden from BasicHttpEntity */
120   public StringEntity setCharset(Charset value) {
121      super.setCharset(value);
122      return this;
123   }
124
125   @Override /* Overridden from BasicHttpEntity */
126   public StringEntity setChunked() {
127      super.setChunked();
128      return this;
129   }
130
131   @Override /* Overridden from BasicHttpEntity */
132   public StringEntity setChunked(boolean value) {
133      super.setChunked(value);
134      return this;
135   }
136
137   @Override /* Overridden from BasicHttpEntity */
138   public StringEntity setContent(Object value) {
139      super.setContent(value);
140      return this;
141   }
142
143   @Override /* Overridden from BasicHttpEntity */
144   public StringEntity setContent(Supplier<?> value) {
145      super.setContent(value);
146      return this;
147   }
148
149   @Override /* Overridden from BasicHttpEntity */
150   public StringEntity setContentEncoding(ContentEncoding value) {
151      super.setContentEncoding(value);
152      return this;
153   }
154
155   @Override /* Overridden from BasicHttpEntity */
156   public StringEntity setContentEncoding(String value) {
157      super.setContentEncoding(value);
158      return this;
159   }
160
161   @Override /* Overridden from BasicHttpEntity */
162   public StringEntity setContentLength(long value) {
163      super.setContentLength(value);
164      return this;
165   }
166
167   @Override /* Overridden from BasicHttpEntity */
168   public StringEntity setContentType(ContentType value) {
169      super.setContentType(value);
170      return this;
171   }
172
173   @Override /* Overridden from BasicHttpEntity */
174   public StringEntity setContentType(String value) {
175      super.setContentType(value);
176      return this;
177   }
178
179   @Override /* Overridden from BasicHttpEntity */
180   public StringEntity setMaxLength(int value) {
181      super.setMaxLength(value);
182      return this;
183   }
184
185   @Override /* Overridden from BasicHttpEntity */
186   public StringEntity setUnmodifiable() {
187      super.setUnmodifiable();
188      return this;
189   }
190
191   @Override /* Overridden from HttpEntity */
192   public void writeTo(OutputStream out) throws IOException {
193      assertArgNotNull("out", out);
194      if (isCached()) {
195         out.write(asBytes());
196      } else {
197         var osw = new OutputStreamWriter(out, getCharset());
198         osw.write(content());
199         osw.flush();
200      }
201   }
202
203   private String content() {
204      return contentOrElse(EMPTY);
205   }
206}