88import java .io .Reader ;
99import java .nio .charset .Charset ;
1010import java .util .Date ;
11+ import java .util .LinkedHashMap ;
1112import java .util .Map ;
1213import java .util .Optional ;
1314
1415import javax .annotation .Nonnull ;
1516
1617import jooby .fn .ExSupplier ;
18+ import jooby .internal .SetHeaderImpl ;
1719
1820import com .google .common .annotations .Beta ;
21+ import com .google .common .collect .ImmutableMap ;
1922
2023/**
2124 * Give you access to the actual HTTP response. You can read/write headers and write HTTP body.
2427 * @since 0.1.0
2528 */
2629@ Beta
27- public interface Response {
30+ public interface Response extends SetHeader {
31+
32+ public class Body implements SetHeader {
33+
34+ private Map <String , String > headers = new LinkedHashMap <>();
35+
36+ private SetHeaderImpl setHeader = new SetHeaderImpl ((name , value ) -> headers .put (name , value ));
37+
38+ private Object content ;
39+
40+ private HttpStatus status ;
41+
42+ private MediaType type ;
43+
44+ public Body (final Object content ) {
45+ content (content );
46+ }
47+
48+ public Body () {
49+ }
50+
51+ public static Body ok () {
52+ return new Body ().status (HttpStatus .OK );
53+ }
54+
55+ public static Body ok (final Object message ) {
56+ return new Body (message ).status (HttpStatus .OK );
57+ }
58+
59+ public static Body accepted () {
60+ return new Body ().status (HttpStatus .ACCEPTED );
61+ }
62+
63+ public static Body accepted (final Object message ) {
64+ return new Body (message ).status (HttpStatus .ACCEPTED );
65+ }
66+
67+ public static Body noContent () {
68+ return new Body ().status (HttpStatus .NO_CONTENT );
69+ }
70+
71+ public Body status (final HttpStatus status ) {
72+ this .status = status ;
73+ return this ;
74+ }
75+
76+ public Body type (final MediaType type ) {
77+ this .type = type ;
78+ return this ;
79+ }
80+
81+ public Body content (final Object content ) {
82+ this .content = requireNonNull (content , "Content is required." );
83+ return this ;
84+ }
85+
86+ public Map <String , String > headers () {
87+ return ImmutableMap .copyOf (headers );
88+ }
89+
90+ public Optional <HttpStatus > status () {
91+ return Optional .ofNullable (status );
92+ }
93+
94+ public Optional <MediaType > type () {
95+ return Optional .ofNullable (type );
96+ }
97+
98+ public Optional <Object > content () {
99+ return Optional .ofNullable (content );
100+ }
101+
102+ @ Override
103+ public Body header (final String name , final char value ) {
104+ setHeader .header (name , value );
105+ return this ;
106+ }
107+
108+ @ Override
109+ public Body header (final String name , final byte value ) {
110+ setHeader .header (name , value );
111+ return this ;
112+ }
113+
114+ @ Override
115+ public Body header (final String name , final short value ) {
116+ setHeader .header (name , value );
117+ return this ;
118+ }
119+
120+ @ Override
121+ public Body header (final String name , final int value ) {
122+ setHeader .header (name , value );
123+ return this ;
124+ }
125+
126+ @ Override
127+ public Body header (final String name , final long value ) {
128+ setHeader .header (name , value );
129+ return this ;
130+ }
131+
132+ @ Override
133+ public Body header (final String name , final float value ) {
134+ setHeader .header (name , value );
135+ return this ;
136+ }
137+
138+ @ Override
139+ public Body header (final String name , final double value ) {
140+ setHeader .header (name , value );
141+ return this ;
142+ }
143+
144+ @ Override
145+ public Body header (final String name , final CharSequence value ) {
146+ setHeader .header (name , value );
147+ return this ;
148+ }
149+
150+ @ Override
151+ public Body header (final String name , final Date value ) {
152+ setHeader .header (name , value );
153+ return this ;
154+ }
155+
156+ @ Override
157+ public String toString () {
158+ return content == null ? "" : content .toString ();
159+ }
160+ }
28161
29162 public class Forwarding implements Response {
30163
@@ -115,7 +248,7 @@ public Response header(final String name, final short value) {
115248 }
116249
117250 @ Override
118- public Response header (final String name , final String value ) {
251+ public Response header (final String name , final CharSequence value ) {
119252 return response .header (name , value );
120253 }
121254
@@ -169,11 +302,21 @@ public void send(final Object body) throws Exception {
169302 response .send (body );
170303 }
171304
305+ @ Override
306+ public void send (final Body body ) throws Exception {
307+ response .send (body );
308+ }
309+
172310 @ Override
173311 public void send (final Object body , final BodyConverter converter ) throws Exception {
174312 response .send (body , converter );
175313 }
176314
315+ @ Override
316+ public void send (final Body body , final BodyConverter converter ) throws Exception {
317+ response .send (body , converter );
318+ }
319+
177320 @ Override
178321 public Formatter format () {
179322 return response .format ();
@@ -300,22 +443,31 @@ default Response cookie(final String name, final String value) {
300443 @ Nonnull
301444 Variant header (@ Nonnull String name );
302445
446+ @ Override
303447 Response header (@ Nonnull String name , char value );
304448
449+ @ Override
305450 Response header (@ Nonnull String name , byte value );
306451
452+ @ Override
307453 Response header (@ Nonnull String name , short value );
308454
455+ @ Override
309456 Response header (@ Nonnull String name , int value );
310457
458+ @ Override
311459 Response header (@ Nonnull String name , long value );
312460
461+ @ Override
313462 Response header (@ Nonnull String name , float value );
314463
464+ @ Override
315465 Response header (@ Nonnull String name , double value );
316466
317- Response header (@ Nonnull String name , String value );
467+ @ Override
468+ Response header (@ Nonnull String name , CharSequence value );
318469
470+ @ Override
319471 Response header (@ Nonnull String name , Date value );
320472
321473 /**
@@ -361,7 +513,22 @@ default Response type(@Nonnull final String type) {
361513 * @throws Exception If the response write fails.
362514 * @see BodyConverter
363515 */
364- void send (@ Nonnull Object body ) throws Exception ;
516+ default void send (@ Nonnull final Object body ) throws Exception {
517+ requireNonNull (body , "A response message is required." );
518+ if (body instanceof Body ) {
519+ send ((Body ) body );
520+ } else {
521+ Body b = new Body (body );
522+ HttpStatus status = status ();
523+ if (status != null ) {
524+ b .status (status );
525+ }
526+ type ().ifPresent (t -> b .type (t ));
527+ send (b );
528+ }
529+ }
530+
531+ void send (@ Nonnull Body body ) throws Exception ;
365532
366533 /**
367534 * Responsible of writing the given body into the HTTP response.
@@ -371,9 +538,26 @@ default Response type(@Nonnull final String type) {
371538 * @throws Exception If the response write fails.
372539 * @see BodyConverter
373540 */
374- void send (@ Nonnull Object body , @ Nonnull BodyConverter converter ) throws Exception ;
541+ default void send (@ Nonnull final Object body , @ Nonnull final BodyConverter converter )
542+ throws Exception {
543+ requireNonNull (body , "A response message is required." );
544+ if (body instanceof Body ) {
545+ send ((Body ) body , converter );
546+ } else {
547+ Body b = new Body (body );
548+ HttpStatus status = status ();
549+ if (status != null ) {
550+ b .status (status );
551+ }
552+ type ().ifPresent (t -> b .type (t ));
553+ send (b , converter );
554+ }
555+ }
375556
376- @ Nonnull Formatter format ();
557+ void send (@ Nonnull Body body , @ Nonnull BodyConverter converter ) throws Exception ;
558+
559+ @ Nonnull
560+ Formatter format ();
377561
378562 default void redirect (final String location ) throws Exception {
379563 redirect (HttpStatus .FOUND , location );
@@ -384,17 +568,20 @@ default void redirect(final String location) throws Exception {
384568 /**
385569 * @return A HTTP status.
386570 */
387- @ Nonnull HttpStatus status ();
571+ @ Nonnull
572+ HttpStatus status ();
388573
389574 /**
390575 * Set the HTTP status.
391576 *
392577 * @param status A HTTP status.
393578 * @return This response.
394579 */
395- @ Nonnull Response status (@ Nonnull HttpStatus status );
580+ @ Nonnull
581+ Response status (@ Nonnull HttpStatus status );
396582
397- @ Nonnull default Response status (final int status ) {
583+ @ Nonnull
584+ default Response status (final int status ) {
398585 return status (HttpStatus .valueOf (status ));
399586 }
400587
0 commit comments