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 java.io.*;
020import java.util.*;
021
022import org.apache.juneau.*;
023import org.apache.juneau.common.utils.*;
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 */
039public class SerializedPojoProcessor implements ResponseProcessor {
040
041   @Override /* ResponseProcessor */
042   public int process(RestOpSession opSession) throws IOException, NotAcceptable, BasicHttpException {
043      RestRequest req = opSession.getRequest();
044      RestResponse res = opSession.getResponse();
045      SerializerMatch sm = res.getSerializerMatch().orElse(null);
046      HttpPartSchema schema = res.getContentSchema().orElse(null);
047
048      Object o = res.getContent(Object.class);
049
050      if (sm != null) {
051         try {
052            Serializer s = sm.getSerializer();
053            MediaType mediaType = res.getMediaType();
054            if (mediaType == null)
055               mediaType = sm.getMediaType();
056
057            MediaType responseType = s.getResponseContentType();
058            if (responseType == null)
059               responseType = mediaType;
060
061            if (req.isPlainText())
062               res.setHeader(ContentType.TEXT_PLAIN);
063            else
064               res.setHeader(ContentType.of(responseType.toString()));
065
066            SerializerSession session = s
067               .createSession()
068               .properties(req.getAttributes().asMap())
069               .javaMethod(req.getOpContext().getJavaMethod())
070               .locale(req.getLocale())
071               .timeZone(req.getTimeZone().orElse(null))
072               .mediaType(mediaType)
073               .apply(WriterSerializerSession.Builder.class, x -> x.streamCharset(res.getCharset()).useWhitespace(req.isPlainText() ? true : null))
074               .schema(schema)
075               .debug(req.isDebug() ? true : null)
076               .uriContext(req.getUriContext())
077               .resolver(req.getVarResolverSession())
078               .build();
079
080            for (Map.Entry<String,String> h : session.getResponseHeaders().entrySet())
081               res.addHeader(h.getKey(), h.getValue());
082
083            if (! session.isWriterSerializer()) {
084               if (req.isPlainText()) {
085                  FinishablePrintWriter w = res.getNegotiatedWriter();
086                  ByteArrayOutputStream baos = new ByteArrayOutputStream();
087                  session.serialize(o, baos);
088                  w.write(StringUtils.toSpacedHex(baos.toByteArray()));
089                  w.flush();
090                  w.finish();
091               } else {
092                  FinishableServletOutputStream os = res.getNegotiatedOutputStream();
093                  session.serialize(o, os);
094                  os.flush();
095                  os.finish();
096               }
097            } else {
098               FinishablePrintWriter w = res.getNegotiatedWriter();
099               session.serialize(o, w);
100               w.flush();
101               w.finish();
102            }
103         } catch (SerializeException e) {
104            throw new InternalServerError(e);
105         }
106         return FINISHED;
107      }
108
109      if (o == null)
110         return FINISHED;
111
112      throw new NotAcceptable(
113         "Unsupported media-type in request header ''Accept'': ''{0}''\n\tSupported media-types: {1}",
114         req.getHeaderParam("Accept").orElse(""), Json5.of(res.getOpContext().getSerializers().getSupportedMediaTypes())
115      );
116   }
117}
118