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.rest.processor;
018
019import static org.apache.juneau.commons.utils.StringUtils.*;
020import static org.apache.juneau.commons.utils.Utils.*;
021
022import java.io.*;
023import org.apache.juneau.*;
024import org.apache.juneau.http.header.*;
025import org.apache.juneau.http.response.*;
026import org.apache.juneau.httppart.*;
027import org.apache.juneau.marshaller.*;
028import org.apache.juneau.rest.*;
029import org.apache.juneau.rest.util.*;
030import org.apache.juneau.serializer.*;
031
032/**
033 * Response handler for plain-old Java objects.
034 *
035 * <h5 class='section'>See Also:</h5><ul>
036 *    <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/ResponseProcessors">Response Processors</a>
037 * </ul>
038 */
039@SuppressWarnings("resource")
040public class SerializedPojoProcessor implements ResponseProcessor {
041
042   @Override /* Overridden from ResponseProcessor */
043   public int process(RestOpSession opSession) throws IOException, NotAcceptable, BasicHttpException {
044      RestRequest req = opSession.getRequest();
045      RestResponse res = opSession.getResponse();
046      SerializerMatch sm = res.getSerializerMatch().orElse(null);
047      HttpPartSchema schema = res.getContentSchema().orElse(null);
048
049      Object o = res.getContent(Object.class);
050
051      if (nn(sm)) {
052         try {
053            Serializer s = sm.getSerializer();
054            MediaType mediaType = res.getMediaType();
055            if (mediaType == null)
056               mediaType = sm.getMediaType();
057
058            MediaType responseType = s.getResponseContentType();
059            if (responseType == null)
060               responseType = mediaType;
061
062            if (req.isPlainText())
063               res.setHeader(ContentType.TEXT_PLAIN);
064            else
065               res.setHeader(ContentType.of(responseType.toString()));
066
067            // @formatter:off
068            SerializerSession session = s
069               .createSession()
070               .properties(req.getAttributes().asMap())
071               .javaMethod(req.getOpContext().getJavaMethod())
072               .locale(req.getLocale())
073               .timeZone(req.getTimeZone().orElse(null))
074               .mediaType(mediaType)
075               .apply(WriterSerializerSession.Builder.class, x -> x.streamCharset(res.getCharset()).useWhitespace(req.isPlainText() ? true : null))
076               .schema(schema)
077               .debug(req.isDebug() ? true : null)
078               .uriContext(req.getUriContext())
079               .resolver(req.getVarResolverSession())
080               .build();
081            // @formatter:on
082
083            for (var h : session.getResponseHeaders().entrySet())
084               res.addHeader(h.getKey(), h.getValue());
085
086            if (! session.isWriterSerializer()) {
087               if (req.isPlainText()) {
088                  FinishablePrintWriter w = res.getNegotiatedWriter();
089                  var baos = new ByteArrayOutputStream();
090                  session.serialize(o, baos);
091                  w.write(toSpacedHex(baos.toByteArray()));
092                  w.flush();
093                  w.finish();
094               } else {
095                  FinishableServletOutputStream os = res.getNegotiatedOutputStream();
096                  session.serialize(o, os);
097                  os.flush();
098                  os.finish();
099               }
100            } else {
101               FinishablePrintWriter w = res.getNegotiatedWriter();
102               session.serialize(o, w);
103               w.flush();
104               w.finish();
105            }
106         } catch (SerializeException e) {
107            throw new InternalServerError(e);
108         }
109         return FINISHED;
110      }
111
112      if (o == null)
113         return FINISHED;
114
115      throw new NotAcceptable("Unsupported media-type in request header ''Accept'': ''{0}''\n\tSupported media-types: {1}", req.getHeaderParam("Accept").orElse(""),
116         Json5.of(res.getOpContext().getSerializers().getSupportedMediaTypes()));
117   }
118}