View Javadoc

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   * Web resource that wraps an existing resource so that it can be transformed.
30   * This wrapper converts relative urls in CSS resources into absolute urls.
31   * 
32   * @since 2.9.0
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       * Copied from AbstractTransformedDownloadableResource and AbstractStringTransformedDownloadableResource
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 }