PageRenderTime 27ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/trunk/org.mwc.asset.comms/docs/restlet_src/org.restlet/org/restlet/engine/util/Conneg.java

https://bitbucket.org/haris_peco/debrief
Java | 429 lines | 199 code | 53 blank | 177 comment | 56 complexity | 0d37f24aada8d2c8df0f2ec69ffc43fd MD5 | raw file
  1. /**
  2. * Copyright 2005-2010 Noelios Technologies.
  3. *
  4. * The contents of this file are subject to the terms of one of the following
  5. * open source licenses: LGPL 3.0 or LGPL 2.1 or CDDL 1.0 or EPL 1.0 (the
  6. * "Licenses"). You can select the license that you prefer but you may not use
  7. * this file except in compliance with one of these Licenses.
  8. *
  9. * You can obtain a copy of the LGPL 3.0 license at
  10. * http://www.opensource.org/licenses/lgpl-3.0.html
  11. *
  12. * You can obtain a copy of the LGPL 2.1 license at
  13. * http://www.opensource.org/licenses/lgpl-2.1.php
  14. *
  15. * You can obtain a copy of the CDDL 1.0 license at
  16. * http://www.opensource.org/licenses/cddl1.php
  17. *
  18. * You can obtain a copy of the EPL 1.0 license at
  19. * http://www.opensource.org/licenses/eclipse-1.0.php
  20. *
  21. * See the Licenses for the specific language governing permissions and
  22. * limitations under the Licenses.
  23. *
  24. * Alternatively, you can obtain a royalty free commercial license with less
  25. * limitations, transferable or non-transferable, directly at
  26. * http://www.noelios.com/products/restlet-engine
  27. *
  28. * Restlet is a registered trademark of Noelios Technologies.
  29. */
  30. package org.restlet.engine.util;
  31. import java.util.ArrayList;
  32. import java.util.List;
  33. import org.restlet.data.CharacterSet;
  34. import org.restlet.data.ClientInfo;
  35. import org.restlet.data.Encoding;
  36. import org.restlet.data.Language;
  37. import org.restlet.data.MediaType;
  38. import org.restlet.data.Metadata;
  39. import org.restlet.data.Preference;
  40. import org.restlet.representation.Variant;
  41. import org.restlet.service.MetadataService;
  42. /**
  43. * Content negotiation algorithm.
  44. *
  45. * @author Jerome Louvel
  46. */
  47. public class Conneg {
  48. /** The enriched list of character set preferences. */
  49. private volatile List<Preference<CharacterSet>> characterSetPrefs;
  50. /** The client preferences. */
  51. private volatile ClientInfo clientInfo;
  52. /** The enriched list of encoding preferences. */
  53. private volatile List<Preference<Encoding>> encodingPrefs;
  54. /** The enriched list of language preferences. */
  55. private volatile List<Preference<Language>> languagePrefs;
  56. /** The enriched list of media type preferences. */
  57. private volatile List<Preference<MediaType>> mediaTypePrefs;
  58. /** The metadata service. */
  59. private volatile MetadataService metadataService;
  60. /**
  61. * Constructor.
  62. *
  63. * @param clientInfo
  64. * @param metadataService
  65. */
  66. public Conneg(ClientInfo clientInfo, MetadataService metadataService) {
  67. this.clientInfo = clientInfo;
  68. this.metadataService = metadataService;
  69. if (clientInfo != null) {
  70. // Get the enriched user preferences
  71. this.languagePrefs = getEnrichedPreferences(clientInfo
  72. .getAcceptedLanguages(), (metadataService == null) ? null
  73. : metadataService.getDefaultLanguage(), Language.ALL);
  74. this.mediaTypePrefs = getEnrichedPreferences(clientInfo
  75. .getAcceptedMediaTypes(), (metadataService == null) ? null
  76. : metadataService.getDefaultMediaType(), MediaType.ALL);
  77. this.characterSetPrefs = getEnrichedPreferences(clientInfo
  78. .getAcceptedCharacterSets(),
  79. (metadataService == null) ? null : metadataService
  80. .getDefaultCharacterSet(), CharacterSet.ALL);
  81. this.encodingPrefs = getEnrichedPreferences(clientInfo
  82. .getAcceptedEncodings(), (metadataService == null) ? null
  83. : metadataService.getDefaultEncoding(), Encoding.ALL);
  84. }
  85. }
  86. /**
  87. * Returns true if the metadata can be added.
  88. *
  89. * @param <T>
  90. * @param metadata
  91. * The metadata to add.
  92. * @param undesired
  93. * The list of proscribed metadata.
  94. * @return True if the metadata can be added.
  95. */
  96. private <T extends Metadata> boolean canAdd(T metadata, List<T> undesired) {
  97. boolean add = true;
  98. if (undesired != null) {
  99. for (T u : undesired) {
  100. if (u.equals(metadata)) {
  101. add = false;
  102. break;
  103. }
  104. }
  105. }
  106. return add;
  107. }
  108. /**
  109. * Returns the enriched list of character set preferences.
  110. *
  111. * @return The enriched list of character set preferences.
  112. */
  113. protected List<Preference<CharacterSet>> getCharacterSetPrefs() {
  114. return characterSetPrefs;
  115. }
  116. /**
  117. * Returns the client preferences.
  118. *
  119. * @return The client preferences.
  120. */
  121. protected ClientInfo getClientInfo() {
  122. return clientInfo;
  123. }
  124. /**
  125. * Returns the enriched list of encoding preferences.
  126. *
  127. * @return The enriched list of encoding preferences.
  128. */
  129. protected List<Preference<Encoding>> getEncodingPrefs() {
  130. return encodingPrefs;
  131. }
  132. /**
  133. * Returns an enriched list of preferences. Contains the user preferences,
  134. * implied user parent preferences (quality between 0.005 and 0.006),
  135. * default preference (quality of 0.003), default parent preference (quality
  136. * of 0.002), all preference (quality of 0.001).<br>
  137. * <br>
  138. * This necessary to compensate the misconfiguration of many browsers which
  139. * don't expose all the metadata actually understood by end users.
  140. *
  141. * @param <T>
  142. * @param userPreferences
  143. * The user preferences to enrich.
  144. * @param defaultValue
  145. * The default value.
  146. * @param allValue
  147. * The ALL value.
  148. * @return The enriched user preferences.
  149. */
  150. @SuppressWarnings("unchecked")
  151. protected <T extends Metadata> List<Preference<T>> getEnrichedPreferences(
  152. List<Preference<T>> userPreferences, T defaultValue, T allValue) {
  153. List<Preference<T>> result = new ArrayList<Preference<T>>();
  154. // 0) List all undesired metadata
  155. List<T> undesired = null;
  156. for (Preference<T> pref : userPreferences) {
  157. if (pref.getQuality() == 0) {
  158. if (undesired == null) {
  159. undesired = new ArrayList<T>();
  160. }
  161. undesired.add(pref.getMetadata());
  162. }
  163. }
  164. // 1) Add the user preferences
  165. result.addAll(userPreferences);
  166. // 2) Add the user parent preferences
  167. T parent;
  168. for (int i = 0; i < result.size(); i++) {
  169. Preference<T> userPref = result.get(i);
  170. parent = (T) userPref.getMetadata().getParent();
  171. // Add the parent, if it is not proscribed.
  172. if ((parent != null)) {
  173. if (canAdd(parent, undesired)) {
  174. result.add(new Preference<T>(parent,
  175. 0.005f + (0.001f * userPref.getQuality())));
  176. }
  177. }
  178. }
  179. // 3) Add the default preference
  180. if (defaultValue != null && canAdd(defaultValue, undesired)) {
  181. Preference<T> defaultPref = new Preference<T>(defaultValue, 0.003f);
  182. result.add(defaultPref);
  183. T defaultParent = (T) defaultValue.getParent();
  184. if (defaultParent != null && canAdd(defaultParent, undesired)) {
  185. result.add(new Preference<T>(defaultParent, 0.002f));
  186. }
  187. }
  188. // 5) Add "all" preference
  189. for (int i = result.size() - 1; i >= 0; i--) {
  190. // Remove any existing preference
  191. if (result.get(i).getMetadata().equals(allValue)) {
  192. result.remove(i);
  193. }
  194. }
  195. result.add(new Preference<T>(allValue, 0.001f));
  196. // 6) Return the enriched preferences
  197. return result;
  198. }
  199. /**
  200. * Returns the enriched list of language preferences.
  201. *
  202. * @return The enriched list of language preferences.
  203. */
  204. protected List<Preference<Language>> getLanguagePrefs() {
  205. return languagePrefs;
  206. }
  207. /**
  208. * Returns the enriched list of media type preferences.
  209. *
  210. * @return The enriched list of media type preferences.
  211. */
  212. protected List<Preference<MediaType>> getMediaTypePrefs() {
  213. return mediaTypePrefs;
  214. }
  215. /**
  216. * Returns the metadata service.
  217. *
  218. * @return The metadata service.
  219. */
  220. protected MetadataService getMetadataService() {
  221. return metadataService;
  222. }
  223. /**
  224. * Returns the best variant representation for a given resource according
  225. * the the client preferences.<br>
  226. * A default language is provided in case the variants don't match the
  227. * client preferences.
  228. *
  229. * @param variants
  230. * The list of variants to compare.
  231. * @return The preferred variant.
  232. * @see <a
  233. * href="http://httpd.apache.org/docs/2.2/en/content-negotiation.html#algorithm">Apache
  234. * content negotiation algorithm</a>
  235. */
  236. public Variant getPreferredVariant(List<? extends Variant> variants) {
  237. Variant result = null;
  238. if ((variants != null) && !variants.isEmpty()) {
  239. float bestScore = -1.0F;
  240. float current;
  241. // Compute the score of each variant
  242. for (Variant variant : variants) {
  243. current = scoreVariant(variant);
  244. if (current > bestScore) {
  245. bestScore = current;
  246. result = variant;
  247. }
  248. }
  249. }
  250. return result;
  251. }
  252. /**
  253. * Scores a character set relatively to enriched client preferences.
  254. *
  255. * @param characterSet
  256. * The character set to score.
  257. * @return The score.
  258. */
  259. public float scoreCharacterSet(CharacterSet characterSet) {
  260. return scoreMetadata(characterSet, getCharacterSetPrefs());
  261. }
  262. /**
  263. * Scores encodings relatively to enriched client preferences.
  264. *
  265. * @param encodings
  266. * The encodings to score.
  267. * @return The score.
  268. */
  269. public float scoreEncodings(List<Encoding> encodings) {
  270. return scoreMetadata(encodings, getEncodingPrefs());
  271. }
  272. /**
  273. * Scores languages relatively to enriched client preferences.
  274. *
  275. * @param languages
  276. * The languages to score.
  277. * @return The score.
  278. */
  279. public float scoreLanguages(List<Language> languages) {
  280. return scoreMetadata(languages, getLanguagePrefs());
  281. }
  282. /**
  283. * Scores a media type relatively to enriched client preferences.
  284. *
  285. * @param mediaType
  286. * The media type to score.
  287. * @return The score.
  288. */
  289. public float scoreMediaType(MediaType mediaType) {
  290. return scoreMetadata(mediaType, getMediaTypePrefs());
  291. }
  292. /**
  293. * Scores a list of metadata relatively to enriched client preferences.
  294. *
  295. * @param metadataList
  296. * The list of metadata to score.
  297. * @return The score.
  298. */
  299. private <T extends Metadata> float scoreMetadata(List<T> metadataList,
  300. List<Preference<T>> prefs) {
  301. float result = -1.0F;
  302. float current;
  303. if ((metadataList != null) && !metadataList.isEmpty()) {
  304. for (Preference<T> pref : prefs) {
  305. for (T metadata : metadataList) {
  306. if (pref.getMetadata().includes(metadata)) {
  307. current = pref.getQuality();
  308. } else {
  309. current = -1.0F;
  310. }
  311. if (current > result) {
  312. result = current;
  313. }
  314. }
  315. }
  316. } else {
  317. result = 0.0F;
  318. }
  319. return result;
  320. }
  321. /**
  322. * Scores a metadata relatively to enriched client preferences.
  323. *
  324. * @param metadata
  325. * The metadata to score.
  326. * @return The score.
  327. */
  328. private <T extends Metadata> float scoreMetadata(T metadata,
  329. List<Preference<T>> prefs) {
  330. float result = -1.0F;
  331. float current;
  332. if (metadata != null) {
  333. for (Preference<? extends Metadata> pref : prefs) {
  334. if (pref.getMetadata().includes(metadata)) {
  335. current = pref.getQuality();
  336. } else {
  337. current = -1.0F;
  338. }
  339. if (current > result) {
  340. result = current;
  341. }
  342. }
  343. } else {
  344. result = 0.0F;
  345. }
  346. return result;
  347. }
  348. /**
  349. * Scores a variant relatively to enriched client preferences.
  350. *
  351. * @param variant
  352. * The variant to score.
  353. * @return The enriched client preferences.
  354. */
  355. public float scoreVariant(Variant variant) {
  356. float result = -1.0F;
  357. float languageScore = scoreLanguages(variant.getLanguages());
  358. if (languageScore != -1.0F) {
  359. float mediaTypeScore = scoreMediaType(variant.getMediaType());
  360. if (mediaTypeScore != -1.0F) {
  361. float characterSetScore = scoreCharacterSet(variant
  362. .getCharacterSet());
  363. if (characterSetScore != -1.0F) {
  364. float encodingScore = scoreEncodings(variant.getEncodings());
  365. if (encodingScore != -1.0F) {
  366. // Return the weighted average score
  367. result = ((languageScore * 4.0F)
  368. + (mediaTypeScore * 3.0F)
  369. + (characterSetScore * 2.0F) + encodingScore) / 9.0F;
  370. }
  371. }
  372. }
  373. }
  374. return result;
  375. }
  376. }