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.CollectionUtils.*; 020import static org.apache.juneau.commons.utils.Utils.*; 021 022import java.io.*; 023import java.util.*; 024 025import org.apache.http.*; 026import org.apache.http.Header; 027import org.apache.juneau.http.annotation.*; 028import org.apache.juneau.http.header.*; 029import org.apache.juneau.http.response.*; 030import org.apache.juneau.rest.*; 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="https://juneau.apache.org/docs/topics/ResponseProcessors">Response Processors</a> 037 * </ul> 038 */ 039@SuppressWarnings("resource") 040public class ResponseBeanProcessor implements ResponseProcessor { 041 042 @Override /* Overridden from ResponseProcessor */ 043 public int process(RestOpSession opSession) throws IOException { 044 045 var req = opSession.getRequest(); 046 var res = opSession.getResponse(); 047 var defaultPartSerializer = req.getOpContext().getPartSerializer(); 048 049 var output = res.getContent(Object.class); 050 051 if (output == null || ! (nn(output.getClass().getAnnotation(Response.class)) || nn(res.getResponseBeanMeta()))) 052 return NEXT; 053 054 var rm = res.getResponseBeanMeta(); 055 if (rm == null) 056 rm = req.getOpContext().getResponseBeanMeta(output); 057 058 var stm = rm.getStatusMethod(); 059 if (nn(stm)) { 060 try { 061 res.setStatus((int)stm.getGetter().invoke(output)); 062 } catch (Exception e) { 063 throw new InternalServerError(e, "Could not get status."); 064 } 065 } else if (rm.getCode() != 0) { 066 res.setStatus(rm.getCode()); 067 } 068 069 for (var hm : rm.getHeaderMethods()) { 070 var n = hm.getPartName().orElse(null); 071 try { 072 var o = hm.getGetter().invoke(output); 073 var ps = hm.getSchema(); 074 if ("*".equals(n)) { 075 for (var o2 : iterate(o)) { 076 var h = (Header)null; 077 if (o2 instanceof Map.Entry o22) { 078 var x = o22; 079 var k = s(x.getKey()); 080 h = new SerializedHeader(k, x.getValue(), hm.getSerializer().orElse(defaultPartSerializer).getPartSession(), ps.getProperty(k), true); 081 } else if (o2 instanceof Header o22) { 082 h = o22; 083 } else if (o2 instanceof NameValuePair o23) { 084 h = BasicHeader.of(o23); 085 } else { 086 throw new InternalServerError("Invalid type ''{0}'' for header ''{1}''", cn(o2), n); 087 } 088 res.addHeader(h); 089 } 090 } else { 091 var h = (Header)null; 092 if (o instanceof Header o2) 093 h = o2; 094 else if (o instanceof NameValuePair o3) 095 h = BasicHeader.of(o3); 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 var bm = rm.getContentMethod(); 106 107 if (nn(bm)) { 108 var m = bm.getGetter(); 109 try { 110 var pt = m.getParameterTypes(); 111 if (pt.length == 1) { 112 var 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 static Iterable<?> iterate(Object o) { 129 if (o == null) 130 return Collections.emptyList(); 131 if (o instanceof Map<?,?> m) 132 return m.entrySet(); 133 if (isArray(o)) 134 return l((Object[])o); 135 if (o instanceof Collection<?> c) 136 return c; 137 throw new InternalServerError("Could not iterate over Headers of type ''{0}''", cn(o)); 138 } 139}