1 package com.atlassian.plugins.rest.common.filter;
2
3 import com.atlassian.annotations.tenancy.TenantAware;
4 import com.google.common.collect.ImmutableMap;
5 import com.sun.jersey.spi.container.ContainerRequest;
6 import com.sun.jersey.spi.container.ContainerRequestFilter;
7 import org.apache.commons.lang.StringUtils;
8 import org.apache.commons.lang.Validate;
9
10 import javax.ws.rs.core.HttpHeaders;
11 import javax.ws.rs.core.UriBuilder;
12 import javax.ws.rs.ext.Provider;
13 import java.net.URI;
14 import java.util.Collection;
15 import java.util.LinkedList;
16 import java.util.List;
17 import java.util.Map;
18 import java.util.regex.Pattern;
19
20 import static com.atlassian.annotations.tenancy.TenancyScope.TENANTLESS;
21 import static javax.ws.rs.core.MediaType.APPLICATION_ATOM_XML;
22 import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
23 import static javax.ws.rs.core.MediaType.APPLICATION_XML;
24 import static javax.ws.rs.core.MediaType.TEXT_HTML;
25 import static javax.ws.rs.core.MediaType.TEXT_PLAIN;
26
27
28
29
30
31
32
33
34
35 @Provider
36 public class ExtensionJerseyFilter implements ContainerRequestFilter {
37 private static final String DOT = ".";
38
39 private final Collection<Pattern> pathExcludePatterns;
40
41 public ExtensionJerseyFilter() {
42 pathExcludePatterns = new LinkedList<Pattern>();
43 }
44
45 public ExtensionJerseyFilter(Collection<String> pathExcludePatterns) {
46 Validate.notNull(pathExcludePatterns);
47 this.pathExcludePatterns = compilePatterns(pathExcludePatterns);
48 }
49
50 @TenantAware(TENANTLESS)
51 final static Map<String, String> EXTENSION_TO_ACCEPT_HEADER = new ImmutableMap.Builder<String, String>()
52 .put("txt", TEXT_PLAIN)
53 .put("htm", TEXT_HTML)
54 .put("html", TEXT_HTML)
55 .put("json", APPLICATION_JSON)
56 .put("xml", APPLICATION_XML)
57 .put("atom", APPLICATION_ATOM_XML)
58 .build();
59
60 public ContainerRequest filter(ContainerRequest request) {
61
62 final String absolutePath = request.getAbsolutePath().toString();
63
64 final String extension = StringUtils.substringAfterLast(absolutePath, DOT);
65 if (shouldFilter("/" + StringUtils.difference(request.getBaseUri().toString(), absolutePath), extension)) {
66 request.getRequestHeaders().putSingle(HttpHeaders.ACCEPT, EXTENSION_TO_ACCEPT_HEADER.get(extension));
67 final String absolutePathWithoutExtension = StringUtils.substringBeforeLast(absolutePath, DOT);
68 request.setUris(request.getBaseUri(), getRequestUri(absolutePathWithoutExtension, request.getQueryParameters()));
69 }
70 return request;
71 }
72
73 private boolean shouldFilter(String restPath, String extension) {
74 for (Pattern pattern : pathExcludePatterns) {
75 if (pattern.matcher(restPath).matches()) {
76 return false;
77 }
78 }
79 return EXTENSION_TO_ACCEPT_HEADER.containsKey(extension);
80 }
81
82 private URI getRequestUri(String absolutePathWithoutExtension, Map<String, List<String>> queryParams) {
83 final UriBuilder requestUriBuilder = UriBuilder.fromPath(absolutePathWithoutExtension);
84 for (Map.Entry<String, List<String>> queryParamEntry : queryParams.entrySet()) {
85 for (String value : queryParamEntry.getValue()) {
86 requestUriBuilder.queryParam(queryParamEntry.getKey(), value);
87 }
88 }
89 return requestUriBuilder.build();
90 }
91
92 private Collection<Pattern> compilePatterns(Collection<String> pathExcludePatterns) {
93 final Collection<Pattern> patterns = new LinkedList<Pattern>();
94 for (String pattern : pathExcludePatterns) {
95 patterns.add(Pattern.compile(pattern));
96 }
97 return patterns;
98 }
99 }