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