View Javadoc
1   package ca.uhn.fhir.rest.api;
2   
3   /*
4    * #%L
5    * HAPI FHIR - Core Library
6    * %%
7    * Copyright (C) 2014 - 2018 University Health Network
8    * %%
9    * Licensed under the Apache License, Version 2.0 (the "License");
10   * you may not use this file except in compliance with the License.
11   * You may obtain a copy of the License at
12   * 
13   *      http://www.apache.org/licenses/LICENSE-2.0
14   * 
15   * Unless required by applicable law or agreed to in writing, software
16   * distributed under the License is distributed on an "AS IS" BASIS,
17   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18   * See the License for the specific language governing permissions and
19   * limitations under the License.
20   * #L%
21   */
22  
23  import ca.uhn.fhir.context.FhirContext;
24  import ca.uhn.fhir.parser.IParser;
25  import org.apache.commons.lang3.ObjectUtils;
26  
27  import java.util.Collections;
28  import java.util.HashMap;
29  import java.util.Map;
30  
31  public enum EncodingEnum {
32  
33  	JSON(Constants.CT_FHIR_JSON, Constants.CT_FHIR_JSON_NEW, Constants.FORMAT_JSON) {
34  		@Override
35  		public IParser newParser(FhirContext theContext) {
36  			return theContext.newJsonParser();
37  		}
38  	},
39  
40  	XML(Constants.CT_FHIR_XML, Constants.CT_FHIR_XML_NEW, Constants.FORMAT_XML) {
41  		@Override
42  		public IParser newParser(FhirContext theContext) {
43  			return theContext.newXmlParser();
44  		}
45  	};
46  
47  	/**
48  	 * "json"
49  	 */
50  	public static final String JSON_PLAIN_STRING = "json";
51  	/**
52  	 * "xml"
53  	 */
54  	public static final String XML_PLAIN_STRING = "xml";
55  	private static Map<String, EncodingEnum> ourContentTypeToEncoding;
56  	private static Map<String, EncodingEnum> ourContentTypeToEncodingLegacy;
57  	private static Map<String, EncodingEnum> ourContentTypeToEncodingStrict;
58  
59  	static {
60  		ourContentTypeToEncoding = new HashMap<>();
61  		ourContentTypeToEncodingLegacy = new HashMap<>();
62  
63  		for (EncodingEnum next : values()) {
64  			ourContentTypeToEncoding.put(next.myResourceContentTypeNonLegacy, next);
65  			ourContentTypeToEncoding.put(next.myResourceContentTypeLegacy, next);
66  			ourContentTypeToEncodingLegacy.put(next.myResourceContentTypeLegacy, next);
67  
68  			/*
69  			 * See #346
70  			 */
71  			ourContentTypeToEncoding.put(next.myResourceContentTypeNonLegacy.replace('+', ' '), next);
72  			ourContentTypeToEncoding.put(next.myResourceContentTypeLegacy.replace('+', ' '), next);
73  			ourContentTypeToEncodingLegacy.put(next.myResourceContentTypeLegacy.replace('+', ' '), next);
74  
75  		}
76  
77  		// Add before we add the lenient ones
78  		ourContentTypeToEncodingStrict = Collections.unmodifiableMap(new HashMap<>(ourContentTypeToEncoding));
79  
80  		/*
81  		 * These are wrong, but we add them just to be tolerant of other
82  		 * people's mistakes
83  		 */
84  		ourContentTypeToEncoding.put("application/json", JSON);
85  		ourContentTypeToEncoding.put("application/xml", XML);
86  		ourContentTypeToEncoding.put("text/json", JSON);
87  		ourContentTypeToEncoding.put("text/xml", XML);
88  
89  		/*
90  		 * Plain values, used for parameter values
91  		 */
92  		ourContentTypeToEncoding.put(JSON_PLAIN_STRING, JSON);
93  		ourContentTypeToEncoding.put(XML_PLAIN_STRING, XML);
94  
95  		ourContentTypeToEncodingLegacy = Collections.unmodifiableMap(ourContentTypeToEncodingLegacy);
96  
97  	}
98  
99  	private String myFormatContentType;
100 	private String myResourceContentTypeLegacy;
101 	private String myResourceContentTypeNonLegacy;
102 
103 	EncodingEnum(String theResourceContentTypeLegacy, String theResourceContentType, String theFormatContentType) {
104 		myResourceContentTypeLegacy = theResourceContentTypeLegacy;
105 		myResourceContentTypeNonLegacy = theResourceContentType;
106 		myFormatContentType = theFormatContentType;
107 	}
108 
109 	public String getFormatContentType() {
110 		return myFormatContentType;
111 	}
112 
113 	/**
114 	 * Will return application/xml+fhir style
115 	 */
116 	public String getResourceContentType() {
117 		return myResourceContentTypeLegacy;
118 	}
119 
120 	/**
121 	 * Will return application/fhir+xml style
122 	 */
123 	public String getResourceContentTypeNonLegacy() {
124 		return myResourceContentTypeNonLegacy;
125 	}
126 
127 	public abstract IParser newParser(FhirContext theContext);
128 
129 	public static EncodingEnum detectEncoding(String theBody) {
130 		EncodingEnum retVal = detectEncodingNoDefault(theBody);
131 		retVal = ObjectUtils.defaultIfNull(retVal, EncodingEnum.XML);
132 		return retVal;
133 	}
134 
135 	public static EncodingEnum detectEncodingNoDefault(String theBody) {
136 		EncodingEnum retVal = null;
137 		for (int i = 0; i < theBody.length() && retVal == null; i++) {
138 			switch (theBody.charAt(i)) {
139 				case '<':
140 					retVal = EncodingEnum.XML;
141 					break;
142 				case '{':
143 					retVal = EncodingEnum.JSON;
144 					break;
145 			}
146 		}
147 		return retVal;
148 	}
149 
150 	/**
151 	 * Returns the encoding for a given content type, or <code>null</code> if no encoding
152 	 * is found.
153 	 * <p>
154 	 * <b>This method is lenient!</b> Things like "application/xml" will return {@link EncodingEnum#XML}
155 	 * even if the "+fhir" part is missing from the expected content type.
156 	 * </p>
157 	 */
158 	public static EncodingEnum forContentType(String theContentType) {
159 		return ourContentTypeToEncoding.get(theContentType);
160 	}
161 
162 
163 	/**
164 	 * Returns the encoding for a given content type, or <code>null</code> if no encoding
165 	 * is found.
166 	 * <p>
167 	 * <b>This method is NOT lenient!</b> Things like "application/xml" will return <code>null</code>
168 	 * </p>
169 	 *
170 	 * @see #forContentType(String)
171 	 */
172 	public static EncodingEnum forContentTypeStrict(String theContentType) {
173 		return ourContentTypeToEncodingStrict.get(theContentType);
174 	}
175 
176 	/**
177 	 * Is the given type a FHIR legacy (pre-DSTU3) content type?
178 	 */
179 	public static boolean isLegacy(String theFormat) {
180 		return ourContentTypeToEncodingLegacy.containsKey(theFormat);
181 	}
182 
183 
184 }