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