View Javadoc
1   /*
2    * Copyright 2022 the original author or authors.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package org.bremersee.exception;
18  
19  import static java.util.Objects.nonNull;
20  import static org.springframework.http.MediaType.APPLICATION_JSON;
21  import static org.springframework.http.MediaType.APPLICATION_XML;
22  import static org.springframework.http.MediaType.TEXT_PLAIN;
23  import static org.springframework.http.MediaType.TEXT_XML;
24  
25  import java.util.Collection;
26  import java.util.List;
27  import java.util.Optional;
28  import lombok.Getter;
29  import org.springframework.http.MediaType;
30  
31  /**
32   * The rest api response type.
33   *
34   * @author Christian Bremer
35   */
36  @Getter
37  public enum RestApiResponseType {
38  
39    /**
40     * Json rest api response type.
41     */
42    JSON(APPLICATION_JSON, MediaType.APPLICATION_JSON_VALUE),
43  
44    /**
45     * Xml rest api response type.
46     */
47    XML(APPLICATION_XML, MediaType.APPLICATION_XML_VALUE),
48  
49    /**
50     * Header rest api response type.
51     */
52    HEADER(TEXT_PLAIN, MediaType.TEXT_PLAIN_VALUE);
53  
54    private static final MediaType APPLICATION_PLUS_JSON = new MediaType("application", "*+json");
55  
56    private static final MediaType APPLICATION_PLUS_XML = new MediaType("application", "*+xml");
57  
58    private final MediaType contentType;
59  
60    private final String contentTypeValue;
61  
62    RestApiResponseType(MediaType contentType, String contentTypeValue) {
63      this.contentType = contentType;
64      this.contentTypeValue = contentTypeValue;
65    }
66  
67    /**
68     * Detect rest api response type by accept header.
69     *
70     * @param accepted the accepted
71     * @return the rest api response content type
72     */
73    public static RestApiResponseType detectByAccepted(List<MediaType> accepted) {
74      RestApiResponseType contentType;
75      if (isJsonAccepted(accepted)) {
76        contentType = JSON;
77      } else if (isXmlAccepted(accepted)) {
78        contentType = XML;
79      } else {
80        contentType = HEADER;
81      }
82      return contentType;
83    }
84  
85    /**
86     * Detect rest api response type by content type.
87     *
88     * @param contentType the content type
89     * @return the rest api response type
90     */
91    public static RestApiResponseType detectByContentType(MediaType contentType) {
92      if (isJson(contentType)) {
93        return JSON;
94      }
95      if (isXml(contentType)) {
96        return XML;
97      }
98      return HEADER;
99    }
100 
101   private static boolean isJson(MediaType contentType) {
102     return nonNull(contentType)
103         && (contentType.isCompatibleWith(APPLICATION_JSON)
104         || contentType.isCompatibleWith(APPLICATION_PLUS_JSON));
105   }
106 
107   private static boolean isJsonAccepted(List<MediaType> accepted) {
108     return Optional.ofNullable(accepted)
109         .stream()
110         .flatMap(Collection::stream)
111         .anyMatch(mediaType -> mediaType.includes(APPLICATION_JSON)
112             || APPLICATION_PLUS_JSON.includes(mediaType)
113             || mediaType.includes(TEXT_PLAIN));
114   }
115 
116   private static boolean isXml(MediaType contentType) {
117     return nonNull(contentType)
118         && (contentType.isCompatibleWith(APPLICATION_XML)
119         || contentType.isCompatibleWith(APPLICATION_PLUS_XML)
120         || TEXT_XML.isCompatibleWith(contentType));
121   }
122 
123   private static boolean isXmlAccepted(List<MediaType> accepted) {
124     return Optional.ofNullable(accepted)
125         .stream()
126         .flatMap(Collection::stream)
127         .anyMatch(mediaType -> mediaType.includes(APPLICATION_XML)
128             || APPLICATION_PLUS_XML.includes(mediaType)
129             || mediaType.includes(TEXT_XML));
130   }
131 
132 }