001// ***************************************************************************************************************************
002// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file *
003// * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file        *
004// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance            *
005// * with the License.  You may obtain a copy of the License at                                                              *
006// *                                                                                                                         *
007// *  http://www.apache.org/licenses/LICENSE-2.0                                                                             *
008// *                                                                                                                         *
009// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an  *
010// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
011// * specific language governing permissions and limitations under the License.                                              *
012// ***************************************************************************************************************************
013package org.apache.juneau.http;
014
015import static org.apache.juneau.internal.IOUtils.*;
016
017import java.io.*;
018import java.util.function.*;
019
020import org.apache.http.*;
021import org.apache.juneau.*;
022import org.apache.juneau.http.header.*;
023import org.apache.juneau.httppart.*;
024import org.apache.juneau.internal.*;
025import org.apache.juneau.serializer.*;
026
027/**
028 * HttpEntity for serializing POJOs as the body of HTTP requests.
029 */
030public class SerializedHttpEntity extends BasicHttpEntity {
031   private final Serializer serializer;
032   private HttpPartSchema schema;
033
034   /**
035    * Creator.
036    *
037    * @param content The POJO to serialize.  Can also be a {@link Reader} or {@link InputStream}.
038    * @param serializer The serializer to use to serialize this response.
039    * @return A new {@link SerializedHttpEntity} with uninitialized serializer and schema.
040    */
041   public static SerializedHttpEntity of(Object content, Serializer serializer) {
042      return new SerializedHttpEntity(content, serializer);
043   }
044
045   /**
046    * Creator.
047    *
048    * @param content The POJO to serialize.  Can also be a {@link Reader} or {@link InputStream}.
049    * @param serializer The serializer to use to serialize this response.
050    * @return A new {@link SerializedHttpEntity} with uninitialized serializer and schema.
051    */
052   public static SerializedHttpEntity of(Supplier<?> content, Serializer serializer) {
053      return new SerializedHttpEntity(content, serializer);
054   }
055
056   /**
057    * Constructor.
058    *
059    * @param content The POJO to serialize.  Can also be a {@link Reader} or {@link InputStream}.
060    * @param serializer The serializer to use to serialize this response.
061    */
062   public SerializedHttpEntity(Object content, Serializer serializer) {
063      super(content, ContentType.of(serializer == null ? null : serializer.getResponseContentType()), null);
064      this.serializer = serializer;
065   }
066
067   /**
068    * Sets the schema to use to serialize the content.
069    *
070    * <p>
071    * Value is ignored if the serializer is not schema-aware.
072    *
073    * @param value The schema.
074    * @return This object (for method chaining).
075    */
076   @FluentSetter
077   public SerializedHttpEntity schema(HttpPartSchema value) {
078      this.schema = value;
079      return this;
080   }
081
082   @Override /* BasicHttpEntity */
083   public void writeTo(OutputStream os) throws IOException {
084      if (isSerializable()) {
085         try {
086            os = new NoCloseOutputStream(os);
087            Object o = getRawContent();
088            if (serializer == null) {
089               os.write(o.toString().getBytes());
090               os.close();
091            } else {
092               SerializerSessionArgs sArgs = SerializerSessionArgs.create().schema(schema);
093               SerializerSession session = serializer.createSession(sArgs);
094               try (Closeable c = session.isWriterSerializer() ? new OutputStreamWriter(os, UTF8) : os) {
095                  session.serialize(o, c);
096               }
097            }
098         } catch (SerializeException e) {
099            throw new BasicRuntimeException(e, "Serialization error on request body.");
100         }
101      } else {
102         super.writeTo(os);
103      }
104   }
105
106   @Override /* BasicHttpEntity */
107   public boolean isRepeatable() {
108      if (isSerializable())
109         return true;
110      return super.isRepeatable();
111   }
112
113   @Override /* BasicHttpEntity */
114   public long getContentLength() {
115      if (isSerializable())
116         return -1;
117      return super.getContentLength();
118   }
119
120   @Override /* BasicHttpEntity */
121   public InputStream getContent() {
122      if (isSerializable()) {
123         try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
124            writeTo(baos);
125            return new ByteArrayInputStream(baos.toByteArray());
126         } catch (IOException e) {
127            throw new RuntimeException(e);
128         }
129      }
130      return super.getContent();
131   }
132
133   private boolean isSerializable() {
134      Object o = getRawContent();
135      return ! (o instanceof InputStream || o instanceof Reader || o instanceof File);
136   }
137
138   // <FluentSetters>
139
140   @Override /* GENERATED - BasicHttpEntity */
141   public SerializedHttpEntity cache() {
142      super.cache();
143      return this;
144   }
145
146   @Override /* GENERATED - BasicHttpEntity */
147   public SerializedHttpEntity cache(boolean value) {
148      super.cache(value);
149      return this;
150   }
151
152   @Override /* GENERATED - BasicHttpEntity */
153   public SerializedHttpEntity chunked() {
154      super.chunked();
155      return this;
156   }
157
158   @Override /* GENERATED - BasicHttpEntity */
159   public SerializedHttpEntity chunked(boolean value) {
160      super.chunked(value);
161      return this;
162   }
163
164   @Override /* GENERATED - BasicHttpEntity */
165   public SerializedHttpEntity contentEncoding(String value) {
166      super.contentEncoding(value);
167      return this;
168   }
169
170   @Override /* GENERATED - BasicHttpEntity */
171   public SerializedHttpEntity contentEncoding(Header value) {
172      super.contentEncoding(value);
173      return this;
174   }
175
176   @Override /* GENERATED - BasicHttpEntity */
177   public SerializedHttpEntity contentLength(long value) {
178      super.contentLength(value);
179      return this;
180   }
181
182   @Override /* GENERATED - BasicHttpEntity */
183   public SerializedHttpEntity contentType(String value) {
184      super.contentType(value);
185      return this;
186   }
187
188   @Override /* GENERATED - BasicHttpEntity */
189   public SerializedHttpEntity contentType(Header value) {
190      super.contentType(value);
191      return this;
192   }
193
194   // </FluentSetters>
195}