View Javadoc

1   package com.atlassian.plugin.webresource;
2   
3   import static com.atlassian.plugin.webresource.AbstractBatchResourceBuilder.skipBatch;
4   
5   import com.atlassian.plugin.ModuleDescriptor;
6   import com.atlassian.plugin.PluginAccessor;
7   import com.atlassian.plugin.elements.ResourceDescriptor;
8   import com.atlassian.plugin.servlet.DownloadableResource;
9   import com.atlassian.plugin.servlet.ServletContextFactory;
10  
11  import org.apache.commons.lang.StringUtils;
12  import org.slf4j.Logger;
13  import org.slf4j.LoggerFactory;
14  
15  import java.util.ArrayList;
16  import java.util.Arrays;
17  import java.util.Collections;
18  import java.util.List;
19  import java.util.Map;
20  import java.util.TreeMap;
21  
22  /**
23   * Default implementation of {@link PluginResourceLocator}.
24   * 
25   * @since 2.2
26   */
27  public class PluginResourceLocatorImpl implements PluginResourceLocator
28  {
29      private static final Logger log = LoggerFactory.getLogger(PluginResourceLocatorImpl.class);
30  
31      final private PluginAccessor pluginAccessor;
32      final private WebResourceUrlProvider webResourceUrlProvider;
33      final private ResourceBatchingConfiguration batchingConfiguration;
34      final private List<DownloadableResourceBuilder> builders;
35  
36      static final String RESOURCE_SOURCE_PARAM = "source";
37      static final String RESOURCE_BATCH_PARAM = "batch";
38  
39      public PluginResourceLocatorImpl(final WebResourceIntegration webResourceIntegration, final ServletContextFactory servletContextFactory, final WebResourceUrlProvider webResourceUrlProvider)
40      {
41          this(webResourceIntegration, servletContextFactory, webResourceUrlProvider, new DefaultResourceBatchingConfiguration());
42      }
43  
44      public PluginResourceLocatorImpl(final WebResourceIntegration webResourceIntegration, final ServletContextFactory servletContextFactory, final WebResourceUrlProvider webResourceUrlProvider,
45                                       final ResourceBatchingConfiguration batchingConfiguration)
46      {
47          this(webResourceIntegration, servletContextFactory, webResourceUrlProvider, new DefaultResourceDependencyResolver(webResourceIntegration, batchingConfiguration), batchingConfiguration);
48      }
49  
50      private PluginResourceLocatorImpl(final WebResourceIntegration webResourceIntegration, final ServletContextFactory servletContextFactory, final WebResourceUrlProvider webResourceUrlProvider,
51                                        final ResourceDependencyResolver dependencyResolver, final ResourceBatchingConfiguration batchingConfiguration)
52      {
53          this.pluginAccessor = webResourceIntegration.getPluginAccessor();
54          this.webResourceUrlProvider = webResourceUrlProvider;
55          this.batchingConfiguration = batchingConfiguration;
56          final SingleDownloadableResourceBuilder singlePluginBuilder = new SingleDownloadableResourceBuilder(pluginAccessor, servletContextFactory);
57          builders = Collections.unmodifiableList(Arrays.asList(new SuperBatchDownloadableResourceBuilder(dependencyResolver, pluginAccessor,
58              webResourceUrlProvider, singlePluginBuilder), new SuperBatchSubResourceBuilder(dependencyResolver, singlePluginBuilder),
59              new ContextBatchDownloadableResourceBuilder(dependencyResolver, pluginAccessor, webResourceUrlProvider, singlePluginBuilder),
60              new ContextBatchSubResourceBuilder(dependencyResolver, singlePluginBuilder), new SingleBatchDownloadableResourceBuilder(pluginAccessor,
61                  webResourceUrlProvider, singlePluginBuilder), singlePluginBuilder));
62  
63      }
64  
65      public boolean matches(final String url)
66      {
67          for (final DownloadableResourceBuilder builder : builders)
68          {
69              if (builder.matches(url))
70              {
71                  return true;
72              }
73          }
74  
75          return false;
76      }
77  
78      public DownloadableResource getDownloadableResource(final String url, final Map<String, String> queryParams)
79      {
80          try
81          {
82              for (final DownloadableResourceBuilder builder : builders)
83              {
84                  if (builder.matches(url))
85                  {
86                      return builder.parse(url, queryParams);
87                  }
88              }
89          }
90          catch (final UrlParseException e)
91          {
92              log.error("Unable to parse URL: " + url, e);
93          }
94          // TODO: It would be better to use Exceptions rather than returning
95          // nulls to indicate an error.
96          return null;
97      }
98  
99      public List<PluginResource> getPluginResources(final String moduleCompleteKey)
100     {
101         final ModuleDescriptor<?> moduleDescriptor = pluginAccessor.getEnabledPluginModule(moduleCompleteKey);
102         if ((moduleDescriptor == null) || !(moduleDescriptor instanceof WebResourceModuleDescriptor))
103         {
104             log.error("Error loading resource \"" + moduleCompleteKey + "\". Resource is not a Web Resource Module");
105             return Collections.emptyList();
106         }
107 
108         final boolean singleMode = !batchingConfiguration.isPluginWebResourceBatchingEnabled();
109         final List<PluginResource> resources = new ArrayList<PluginResource>();
110 
111         for (final ResourceDescriptor resourceDescriptor : moduleDescriptor.getResourceDescriptors())
112         {
113             if (singleMode || skipBatch(resourceDescriptor))
114             {
115                 final boolean cache = !"false".equalsIgnoreCase(resourceDescriptor.getParameter("cache"));
116                 resources.add(new SinglePluginResource(resourceDescriptor.getName(), moduleDescriptor.getCompleteKey(), cache,
117                     resourceDescriptor.getParameters()));
118             }
119             else
120             {
121                 final BatchPluginResource batchResource = createBatchResource(moduleDescriptor.getCompleteKey(), resourceDescriptor);
122                 if (!resources.contains(batchResource))
123                 {
124                     resources.add(batchResource);
125                 }
126             }
127         }
128         return resources;
129     }
130 
131     // package protected so we can test it
132     String[] splitLastPathPart(final String resourcePath)
133     {
134         int indexOfSlash = resourcePath.lastIndexOf('/');
135         if (resourcePath.endsWith("/")) // skip over the trailing slash
136         {
137             indexOfSlash = resourcePath.lastIndexOf('/', indexOfSlash - 1);
138         }
139 
140         if (indexOfSlash < 0)
141         {
142             return null;
143         }
144 
145         return new String[] { resourcePath.substring(0, indexOfSlash + 1), resourcePath.substring(indexOfSlash + 1) };
146     }
147 
148     private BatchPluginResource createBatchResource(final String moduleCompleteKey, final ResourceDescriptor resourceDescriptor)
149     {
150         final String name = resourceDescriptor.getName();
151         final String type = name.substring(name.lastIndexOf(".") + 1);
152         final Map<String, String> params = new TreeMap<String, String>();
153         for (final String param : BATCH_PARAMS)
154         {
155             final String value = resourceDescriptor.getParameter(param);
156             if (StringUtils.isNotEmpty(value))
157             {
158                 params.put(param, value);
159             }
160         }
161 
162         return new BatchPluginResource(moduleCompleteKey, type, params, Collections.<DownloadableResource> emptyList());
163     }
164 
165     public String getResourceUrl(final String moduleCompleteKey, final String resourceName)
166     {
167         return webResourceUrlProvider.getResourceUrl(moduleCompleteKey, resourceName);
168     }
169 }