1 package com.atlassian.plugin.webresource;
2
3 import static com.atlassian.plugin.servlet.AbstractFileServerServlet.PATH_SEPARATOR;
4 import static com.atlassian.plugin.webresource.SinglePluginResource.URL_PREFIX;
5 import static com.atlassian.plugin.webresource.transformer.SearchAndReplacer.create;
6 import static com.atlassian.plugin.webresource.transformer.TransformerUtils.transformAndStreamResource;
7
8 import com.atlassian.plugin.ModuleDescriptor;
9 import com.atlassian.plugin.elements.ResourceDescriptor;
10 import com.atlassian.plugin.servlet.DownloadException;
11 import com.atlassian.plugin.servlet.DownloadableResource;
12 import com.atlassian.util.concurrent.LazyReference;
13
14 import org.apache.commons.lang.StringUtils;
15
16 import com.google.common.base.Function;
17 import com.google.common.base.Predicate;
18
19 import java.io.IOException;
20 import java.io.OutputStream;
21 import java.nio.charset.Charset;
22 import java.util.regex.Matcher;
23 import java.util.regex.Pattern;
24
25 import javax.servlet.http.HttpServletRequest;
26 import javax.servlet.http.HttpServletResponse;
27
28
29
30
31
32
33
34 final class RelativeURLTransformResource implements DownloadableResource
35 {
36 static final Charset UTF8 = Charset.forName("UTF-8");
37 static final Pattern CSS_URL_PATTERN = Pattern.compile("url\\s*\\(\\s*+([\"'])?+(?!/|https?://|data:)");
38
39 static boolean matches(final ResourceDescriptor resource)
40 {
41 return CssWebResource.FORMATTER.matches(resource.getName());
42 }
43
44 static final Predicate<ResourceDescriptor> matcher = new Predicate<ResourceDescriptor>()
45 {
46 public boolean apply(final ResourceDescriptor input)
47 {
48 return matches(input);
49 }
50 };
51
52 private final DownloadableResource originalResource;
53 private final LazyReference<String> urlPrefix;
54
55 RelativeURLTransformResource(final WebResourceUrlProvider webResourceUrlProvider, final ModuleDescriptor<?> moduleDescriptor, final DownloadableResource originalResource)
56 {
57 this.originalResource = originalResource;
58 urlPrefix = new LazyReference<String>()
59 {
60 @Override
61 protected String create()
62 {
63 final String version = moduleDescriptor.getPlugin().getPluginInformation().getVersion();
64 return webResourceUrlProvider.getStaticResourcePrefix(version, UrlMode.RELATIVE) + URL_PREFIX + PATH_SEPARATOR + moduleDescriptor.getCompleteKey() + PATH_SEPARATOR;
65 }
66 };
67 }
68
69 CharSequence transform(final CharSequence originalContent)
70 {
71 final Function<Matcher, CharSequence> replacer = new Function<Matcher, CharSequence>()
72 {
73 public CharSequence apply(final Matcher matcher)
74 {
75 return new StringBuilder(matcher.group()).append(urlPrefix.get());
76 }
77 };
78 return create(CSS_URL_PATTERN, replacer).replaceAll(originalContent);
79 }
80
81
82
83
84 public boolean isResourceModified(final HttpServletRequest request, final HttpServletResponse response)
85 {
86 return originalResource.isResourceModified(request, response);
87 }
88
89 public void serveResource(final HttpServletRequest request, final HttpServletResponse response) throws DownloadException
90 {
91 final String contentType = getContentType();
92 if (StringUtils.isNotBlank(contentType))
93 {
94 response.setContentType(contentType);
95 }
96
97 try
98 {
99 streamResource(response.getOutputStream());
100 }
101 catch (final IOException e)
102 {
103 throw new DownloadException(e);
104 }
105 }
106
107 public void streamResource(final OutputStream out) throws DownloadException
108 {
109 transformAndStreamResource(originalResource, UTF8, out, new Function<CharSequence, CharSequence>()
110 {
111 public CharSequence apply(final CharSequence originalContent)
112 {
113 return transform(originalContent);
114 }
115 });
116 }
117
118 public String getContentType()
119 {
120 return originalResource.getContentType();
121 }
122 }