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.rest.processor;
014
015import static org.apache.juneau.common.internal.StringUtils.*;
016import static org.apache.juneau.internal.ClassUtils.*;
017import static org.apache.juneau.internal.CollectionUtils.*;
018
019import java.io.*;
020import java.lang.reflect.*;
021import java.util.*;
022
023import org.apache.juneau.rest.*;
024import org.apache.http.*;
025import org.apache.http.Header;
026import org.apache.juneau.http.annotation.*;
027import org.apache.juneau.http.header.*;
028import org.apache.juneau.http.response.*;
029import org.apache.juneau.httppart.*;
030import org.apache.juneau.httppart.bean.*;
031
032/**
033 * Response handler for {@link Response @Response}-annotated objects.
034 *
035 * <h5 class='section'>See Also:</h5><ul>
036 *    <li class='link'><a class="doclink" href="../../../../../index.html#jrs.ResponseProcessors">Response Processors</a>
037 * </ul>
038 */
039public final class ResponseBeanProcessor implements ResponseProcessor {
040
041   @Override /* ResponseProcessor */
042   public int process(RestOpSession opSession) throws IOException {
043
044      RestRequest req = opSession.getRequest();
045      RestResponse res = opSession.getResponse();
046      HttpPartSerializer defaultPartSerializer = req.getOpContext().getPartSerializer();
047
048      Object output = res.getContent(Object.class);
049
050      if (output == null || ! (output.getClass().getAnnotation(Response.class) != null || res.getResponseBeanMeta() != null))
051         return NEXT;
052
053      ResponseBeanMeta rm = res.getResponseBeanMeta();
054      if (rm == null)
055         rm = req.getOpContext().getResponseBeanMeta(output);
056
057      ResponseBeanPropertyMeta stm = rm.getStatusMethod();
058      if (stm != null) {
059         try {
060            res.setStatus((int)stm.getGetter().invoke(output));
061         } catch (Exception e) {
062            throw new InternalServerError(e, "Could not get status.");
063         }
064      } else if (rm.getCode() != 0) {
065         res.setStatus(rm.getCode());
066      }
067
068      for (ResponseBeanPropertyMeta hm : rm.getHeaderMethods()) {
069         String n = hm.getPartName().orElse(null);
070         try {
071            Object o = hm.getGetter().invoke(output);
072            HttpPartSchema ps = hm.getSchema();
073            if ("*".equals(n)) {
074               for (Object o2 : iterate(o)) {
075                  Header h = null;
076                  if (o2 instanceof Map.Entry) {
077                     @SuppressWarnings("rawtypes")
078                     Map.Entry x = (Map.Entry)o2;
079                     String k = stringify(x.getKey());
080                     h = new SerializedHeader(k, x.getValue(), hm.getSerializer().orElse(defaultPartSerializer).getPartSession(), ps.getProperty(k), true);
081                  } else if (o2 instanceof Header) {
082                     h = (Header)o2;
083                  } else if (o2 instanceof NameValuePair) {
084                     h = BasicHeader.of((NameValuePair)o2);
085                  } else {
086                     throw new InternalServerError("Invalid type ''{0}'' for header ''{1}''", className(o2), n);
087                  }
088                  res.addHeader(h);
089               }
090            } else {
091               Header h = null;
092               if (o instanceof Header)
093                  h = (Header)o;
094               else if (o instanceof NameValuePair)
095                  h = BasicHeader.of((NameValuePair)o);
096               else
097                  h = new SerializedHeader(n, o, hm.getSerializer().orElse(defaultPartSerializer).getPartSession(), ps, true);
098               res.addHeader(h);
099            }
100         } catch (Exception e) {
101            throw new InternalServerError(e, "Could not set header ''{0}''", n);
102         }
103      }
104
105      ResponseBeanPropertyMeta bm = rm.getContentMethod();
106
107      if (bm != null) {
108         Method m = bm.getGetter();
109         try {
110            Class<?>[] pt = m.getParameterTypes();
111            if (pt.length == 1) {
112               Class<?> ptt = pt[0];
113               if (ptt == OutputStream.class)
114                  m.invoke(output, res.getOutputStream());
115               else if (ptt == Writer.class)
116                  m.invoke(output, res.getWriter());
117               return 1;
118            }
119            res.setContent(m.invoke(output));
120         } catch (Exception e) {
121            throw new InternalServerError(e, "Could not get content.");
122         }
123      }
124
125      return NEXT;  // Let PojoProcessor serialize it.
126   }
127
128   private Iterable<?> iterate(Object o) {
129      if (o == null)
130         return Collections.emptyList();
131      if (o instanceof Map)
132         return ((Map<?,?>)o).entrySet();
133      if (o.getClass().isArray())
134         return alist((Object[])o);
135      if (o instanceof Collection)
136         return (Collection<?>)o;
137      throw new InternalServerError("Could not iterate over Headers of type ''{0}''", className(o));
138   }
139}