View Javadoc

1   package com.atlassian.plugin.webresource;
2   
3   import static com.atlassian.plugin.util.Assertions.notNull;
4   import static com.google.common.collect.ImmutableMap.copyOf;
5   import static com.google.common.collect.Iterables.addAll;
6   import static com.google.common.collect.Iterables.concat;
7   import static com.google.common.collect.Iterables.contains;
8   import static com.google.common.collect.Iterables.filter;
9   import static com.google.common.collect.Iterables.transform;
10  
11  import com.atlassian.plugin.ModuleDescriptor;
12  
13  import com.google.common.base.Predicate;
14  import com.google.common.base.Supplier;
15  import com.google.common.collect.ImmutableSet;
16  import com.google.common.collect.Iterables;
17  import com.google.common.collect.Lists;
18  import com.google.common.collect.Sets;
19  
20  import java.io.IOException;
21  import java.io.StringWriter;
22  import java.io.Writer;
23  import java.util.ArrayList;
24  import java.util.Arrays;
25  import java.util.Collections;
26  import java.util.HashMap;
27  import java.util.HashSet;
28  import java.util.Iterator;
29  import java.util.LinkedHashSet;
30  import java.util.LinkedList;
31  import java.util.List;
32  import java.util.Map;
33  import java.util.Set;
34  
35  import javax.annotation.Nullable;
36  
37  import org.apache.commons.collections.CollectionUtils;
38  
39  /**
40   * A handy super-class that handles most of the resource management.
41   * <p/>
42   * To use this manager, you need to have the following UrlRewriteFilter code:
43   * <pre>
44   * &lt;rule>
45   * &lt;from>^/s/(.*)/_/(.*)&lt;/from>
46   * &lt;run class="com.atlassian.plugin.servlet.ResourceDownloadUtils" method="addCachingHeaders" />
47   * &lt;to type="forward">/$2&lt;/to>
48   * &lt;/rule>
49   * </pre>
50   * <p/>
51   * Sub-classes should implement the abstract methods
52   */
53  public class WebResourceManagerImpl implements WebResourceManager
54  {
55      static final String STATIC_RESOURCE_PREFIX = "s";
56      static final String STATIC_RESOURCE_SUFFIX = "_";
57  
58      static final String REQUEST_CACHE_RESOURCE_KEY = "plugin.webresource.names";
59      static final String REQUEST_CACHE_CONTEXT_KEY = "plugin.webresource.contexts";
60  
61      protected final WebResourceIntegration webResourceIntegration;
62      protected final PluginResourceLocator pluginResourceLocator;
63      private final WebResourceUrlProvider webResourceUrlProvider;
64      protected final ResourceBatchingConfiguration batchingConfiguration;
65      protected final ResourceDependencyResolver dependencyResolver;
66  
67      protected static final List<WebResourceFormatter> webResourceFormatters = Arrays.asList(CssWebResource.FORMATTER, JavascriptWebResource.FORMATTER);
68  
69      private static final boolean IGNORE_SUPERBATCHING = false;
70  
71      public WebResourceManagerImpl(final PluginResourceLocator pluginResourceLocator, final WebResourceIntegration webResourceIntegration, final WebResourceUrlProvider webResourceUrlProvider)
72      {
73          this(pluginResourceLocator, webResourceIntegration, webResourceUrlProvider, new DefaultResourceBatchingConfiguration());
74      }
75  
76      public WebResourceManagerImpl(final PluginResourceLocator pluginResourceLocator, final WebResourceIntegration webResourceIntegration, final WebResourceUrlProvider webResourceUrlProvider, final ResourceBatchingConfiguration batchingConfiguration)
77      {
78          this(pluginResourceLocator, webResourceIntegration, webResourceUrlProvider, batchingConfiguration, new DefaultResourceDependencyResolver(
79              webResourceIntegration, batchingConfiguration));
80      }
81  
82      public WebResourceManagerImpl(final PluginResourceLocator pluginResourceLocator, final WebResourceIntegration webResourceIntegration, final WebResourceUrlProvider webResourceUrlProvider, final ResourceBatchingConfiguration batchingConfiguration, final ResourceDependencyResolver dependencyResolver)
83      {
84          this.pluginResourceLocator = notNull("pluginResourceLocator", pluginResourceLocator);
85          this.webResourceIntegration = notNull("webResourceIntegration", webResourceIntegration);
86          this.webResourceUrlProvider = notNull("webResourceUrlProvider", webResourceUrlProvider);
87          this.batchingConfiguration = notNull("batchingConfiguration", batchingConfiguration);
88          this.dependencyResolver = notNull("dependencyResolver", dependencyResolver);
89      }
90  
91      public void requireResource(final String moduleCompleteKey)
92      {
93          final boolean batchingEnabled = batchingConfiguration.isSuperBatchingEnabled();
94          addAll(getIncludedResourceNames(), toModuleKeys(dependencyResolver.getDependencies(moduleCompleteKey, batchingEnabled)));
95      }
96  
97      public void requireResourcesForContext(final String context)
98      {
99          getIncludedContexts().add(context);
100     }
101 
102     public void includeResources(final Iterable<String> moduleCompleteKeys, final Writer writer, final UrlMode urlMode)
103     {
104         Iterable<String> resources = Lists.newArrayList();
105         for (final String moduleCompleteKey : moduleCompleteKeys)
106         {
107             // Include resources from the super batch as we don't include the super batch itself
108             final Iterable<String> dependencies = toModuleKeys(dependencyResolver.getDependencies(moduleCompleteKey, false));
109             resources = concat(resources, dependencies);
110         }
111 
112         // Resolve duplicates
113         resources = ImmutableSet.copyOf(resources);
114         writeResourceTags(getModuleResources(resources, Collections.<String> emptyList(), DefaultWebResourceFilter.INSTANCE), writer, urlMode);
115     }
116 
117     /**
118      * This is the equivalent of of calling {@link #includeResources(Writer, UrlMode, WebResourceFilter)} with
119      * the given url mode and a {@link DefaultWebResourceFilter}.
120      *
121      * @see #includeResources(Writer, UrlMode, WebResourceFilter)
122      */
123     public void includeResources(final Writer writer, final UrlMode urlMode)
124     {
125         includeResources(writer, urlMode, DefaultWebResourceFilter.INSTANCE);
126     }
127 
128     /**
129      * Writes out the resource tags to the previously required resources called via requireResource methods for the
130      * specified url mode and resource filter. Note that this method will clear the list of previously required resources.
131      *
132      * @param writer the writer to write the links to
133      * @param urlMode the url mode to write resource url links in
134      * @param webResourceFilter the resource filter to filter resources on
135      * @since 2.4
136      */
137     public void includeResources(final Writer writer, final UrlMode urlMode, final WebResourceFilter webResourceFilter)
138     {
139         writeIncludedResources(writer, urlMode, webResourceFilter);
140         clear();
141     }
142 
143     /**
144      * This is the equivalent of calling {@link #getRequiredResources(UrlMode, WebResourceFilter)} with the given url
145      * mode and a {@link DefaultWebResourceFilter}.
146      *
147      * @see #getRequiredResources(UrlMode, WebResourceFilter)
148      */
149     public String getRequiredResources(final UrlMode urlMode)
150     {
151         return getRequiredResources(urlMode, DefaultWebResourceFilter.INSTANCE);
152     }
153 
154     /**
155      * Returns a String of the resources tags to the previously required resources called via requireResource methods
156      * for the specified url mode and resource filter. Note that this method will NOT clear the list of previously
157      * required resources.
158      *
159      * @param urlMode the url mode to write out the resource tags
160      * @param filter the web resource filter to filter resources on
161      * @return a String of the resource tags
162      * @since 2.4
163      */
164     public String getRequiredResources(final UrlMode urlMode, final WebResourceFilter filter)
165     {
166         return writeIncludedResources(new StringWriter(), urlMode, filter).toString();
167     }
168     
169     /**
170      * Get the resources that have been required but excluding certain resource keys and certain contexts.
171      * <p/>
172      * You should note that the WebResourceManager cannot break context batch resources down beyond the 
173      * granularity of the context so excluding particular resource keys does not necessary exclude them
174      * from a context batch. To safely use this method it is expected that after the initial page load any 
175      * subsequent "dynamic" requests for resources should be at the granularity of individual resources and 
176      * not contexts. However you can request contexts if you are confident that there hasn't been an 
177      * overlap of contexts and dynamically requested macros. A typical safe example is in Confluence when
178      * rendering macros the macro rendering process will have requested individual resources which will
179      * not exist in any contexts.
180      * <p/>
181      * This method is available for use by sub-classes but is not part of the public interface since it does
182      * not form a complete solution for dynamic resource handling.
183      * 
184      * @param urlMode the url mode to write out the resource tags
185      * @param filter the web resource filter to filter resources on
186      * @param excludedResourceKeys the complete key of resources to be excluded. These exclusion will not apply to any requested contexts
187      * so if a context happens to include these resource keys it will still be served (unless excluded as a context).
188      * @param excludedContexts contexts to be excluded when the tags are written
189      * @return a String of the resource tags
190      * @since 2.12.5
191      */
192     protected String getRequiredResources(UrlMode urlMode, WebResourceFilter webResourceFilter, Set<String> excludedResourceKeys, List<String> excludedContexts)
193     {
194         return writeIncludedResources(new StringWriter(), urlMode, webResourceFilter, excludedResourceKeys, excludedContexts).toString();
195     }
196     
197     /**
198      * Write all currently included resources to the given writer.
199      */
200     private <W extends Writer> W writeIncludedResources(final W writer, final UrlMode urlMode, final WebResourceFilter filter)
201     {
202         return writeIncludedResources(writer, urlMode, filter, Collections.<String>emptySet(), Collections.<String>emptyList());
203     }
204     
205     /**
206      * Write the resource tags request to the given writer but exclude certain resources and contexts. A typical use case would
207      * be of a single page application which progressively requires further resources as further parts of the application are 
208      * loaded. The application would use this method and supply the resource keys and contexts it already knows about so that
209      * duplicate resources do not end up being served.
210      * <p/>
211      * Note that a context batch cannot be broken down into individual resource keys in the current WebResourceManager 
212      * implementation so the contents of context batches are not affected by any excluded resource keys. You can only 
213      * affect the context batches served by specifying excluded contexts. Another implication of this is that is
214      * super batching is configured then the super batch will always be returned (for this method to be useful you
215      * should have super batching disabled).
216      * 
217      * @param writer
218      * @param urlMode
219      * @param filter
220      * @param excludedResourceKeys the complete key of resources to be excluded. These exclusion will not apply to any requested contexts
221      * so if a context happens to include these resource keys it will still be served (unless excluded as a context).
222      * @param excludedContexts contexts to be excluded when the tags are written
223      * @return the requested resources formatted as HTML tags with excluded contexts and resources ignored.
224      */
225     private <W extends Writer> W writeIncludedResources(final W writer, final UrlMode urlMode, final WebResourceFilter filter, 
226             final Set<String> excludedResourceKeys, final List<String> excludedContexts)
227     {
228         final ContextBatchBuilder builder = new ContextBatchBuilder(pluginResourceLocator, dependencyResolver, batchingConfiguration);
229         
230         final Iterable<PluginResource> resourcesToInclude = concat(getSuperBatchResources(filter), 
231                 builder.build(new ArrayList<String>(getIncludedContexts()), excludedContexts, filter));
232 
233         for (final String skippedResource : builder.getSkippedResources())
234         {
235             requireResource(skippedResource);
236         }
237         
238         final Iterable<PluginResource> moduleResources = getModuleResources(getIncludedResourceNames(), builder.getAllIncludedResources(), filter);
239         Iterable<PluginResource> completedModuleResources = moduleResources;
240         
241         // remove the resources we want to exclude
242         if (excludedResourceKeys != null)
243         {
244             completedModuleResources = filter(moduleResources, new Predicate<PluginResource>() {
245                 @Override
246                 public boolean apply(@Nullable PluginResource resource)
247                 {
248                     return !excludedResourceKeys.contains(resource.getModuleCompleteKey());
249                 }
250             });
251         }
252         
253         return writeResourceTags(concat(resourcesToInclude, completedModuleResources), writer, urlMode);        
254     }    
255 
256     /**
257      * Get all super-batch resources that match the given filter. If superbatching is disabled this will just
258      * return the empty list.
259      *
260      * Package private so it can be tested independently.
261      */
262     List<PluginResource> getSuperBatchResources(final WebResourceFilter filter)
263     {
264         if (!batchingConfiguration.isSuperBatchingEnabled())
265         {
266             return Collections.emptyList();
267         }
268 
269         final Iterable<WebResourceModuleDescriptor> superBatchModuleKeys = dependencyResolver.getSuperBatchDependencies();
270         final List<PluginResource> resources = new ArrayList<PluginResource>();
271 
272         // This is necessarily quite complicated. We need distinct superbatch resources for each combination of
273         // resourceFormatter (i.e. separate CSS or JS resources), and also each unique combination of
274         // BATCH_PARAMS (i.e. separate superbatches for print stylesheets, IE only stylesheets, and IE only print
275         // stylesheets if they ever exist in the future)
276         for (final WebResourceFormatter formatter : webResourceFormatters)
277         {
278             final Map<Map<String,String>,SuperBatchPluginResource> resourceByParams = new HashMap<Map<String,String>,SuperBatchPluginResource>();
279 
280             for (final WebResourceModuleDescriptor moduleDescriptor : superBatchModuleKeys)
281             {
282                 for (final PluginResource pluginResource : pluginResourceLocator.getPluginResources(moduleDescriptor.getCompleteKey()))
283                 {
284                     if (formatter.matches(pluginResource.getResourceName()) && filter.matches(pluginResource.getResourceName()))
285                     {
286                         final Map<String, String> batchParamsMap = new HashMap<String, String>(PluginResourceLocator.BATCH_PARAMS.length);
287                         for (final String s : PluginResourceLocator.BATCH_PARAMS)
288                         {
289                             batchParamsMap.put(s, pluginResource.getParams().get(s));
290                         }
291 
292                         if (!resourceByParams.containsKey(batchParamsMap))
293                         {
294                             resourceByParams.put(batchParamsMap, SuperBatchPluginResource.createBatchFor(pluginResource));
295                         }
296                         
297                         SuperBatchPluginResource superBatchPluginResource = resourceByParams.get(batchParamsMap);
298                         
299                         // record the content of each super batch to enable front-end dependency tracking
300                         BatchedWebResourceDescriptor descriptor = new BatchedWebResourceDescriptor(pluginResource.getVersion(webResourceIntegration), pluginResource.getModuleCompleteKey());
301                         superBatchPluginResource.addBatchedWebResourceDescriptor(descriptor);
302                     }
303                 }
304             }
305             
306             resources.addAll(resourceByParams.values());            
307         }
308         
309         return resources;
310     }
311 
312     /**
313      * Write the tags for the given set of resources to the writer. Writing will be done in order of
314      * webResourceFormatters so that all CSS resources will be output before Javascript.
315      */
316     private <W extends Writer> W writeResourceTags(final Iterable<PluginResource> resourcesToInclude, final W writer, final UrlMode urlMode)
317     {
318         List<PluginResource> localCopyOfResources = Lists.newArrayList(resourcesToInclude);
319         
320         for (final WebResourceFormatter formatter : webResourceFormatters)
321         {
322             for (final Iterator<PluginResource> iter = localCopyOfResources.iterator(); iter.hasNext();)
323             {
324                 final PluginResource resource = iter.next();
325                 if (formatter.matches(resource.getResourceName()))
326                 {
327                     writeResourceTag(urlMode, resource, formatter, writer);
328                     iter.remove();
329                 }
330             }
331         }
332 
333         for (final PluginResource resource : localCopyOfResources)
334         {
335             writeContentAndSwallowErrors(writer, "<!-- Error loading resource \"", resource.getModuleCompleteKey(),
336                 "\".  No resource formatter matches \"", resource.getResourceName(), "\" -->\n");
337         }
338         return writer;
339     }
340 
341     private void writeResourceTag(final UrlMode urlMode, final PluginResource resource, final WebResourceFormatter formatter, final Writer writer)
342     {
343         final String prefix;
344         if (resource.isCacheSupported())
345         {
346             prefix = webResourceUrlProvider.getStaticResourcePrefix(resource.getVersion(webResourceIntegration), urlMode);
347         }
348         else
349         {
350             prefix = webResourceUrlProvider.getBaseUrl(urlMode);
351         }
352         
353         String formattedResource = formatter.formatResource(prefix + resource.getUrl(), resource.getParams());
354         
355         // insert the dependency information into the formatted resource
356         if (batchingConfiguration.isBatchContentTrackingEnabled())
357         {
358             formattedResource = BatchResourceContentsWebFormatter.insertBatchResourceContents(resource, formattedResource);
359         }
360         
361         writeContentAndSwallowErrors(writer, formattedResource);
362     }
363     
364     public void requireResource(final String moduleCompleteKey, final Writer writer, final UrlMode urlMode)
365     {
366         final Iterable<String> allDependentModuleKeys = toModuleKeys(dependencyResolver.getDependencies(moduleCompleteKey, IGNORE_SUPERBATCHING));
367         final Iterable<String> empty = Collections.<String> emptyList();
368         final Iterable<PluginResource> resourcesToInclude = getModuleResources(allDependentModuleKeys, empty, DefaultWebResourceFilter.INSTANCE);
369         writeResourceTags(resourcesToInclude, writer, urlMode);
370     }
371 
372     public String getResourceTags(final String moduleCompleteKey, final UrlMode urlMode)
373     {
374         final StringWriter writer = new StringWriter();
375         requireResource(moduleCompleteKey, writer, urlMode);
376         return writer.toString();
377     }
378     
379     /**
380      * Create the HTML tags necessary for requesting the supplied contexts <strong>in addition</strong> to any
381      * contexts already requested of the WebResourceManager (using {@link #requireResourcesForContext(String)}).
382      * <p/>
383      * This is intended to be useful in the case of storing in a page render the requests that will need to
384      * be made if you want to dynamically add additional contexts after the initial render. This doesn't form
385      * a complete solution to dynamically adding resources to a page which is the reason this method is not
386      * part of the public API.
387      *  
388      * @param contexts the additional contexts to create tags for
389      * @return the HTML tags required to request the additional context resources
390      */
391     protected String getResourceTagsForAdditionalContexts(final List<String> contexts)
392     {
393         return getResourceTagsForAdditionalContexts(contexts, UrlMode.AUTO, DefaultWebResourceFilter.INSTANCE);
394     }
395     
396     protected String getResourceTagsForAdditionalContexts(final List<String> contexts, final UrlMode urlMode, final WebResourceFilter filter)
397     {
398         final ContextBatchBuilder builder = new ContextBatchBuilder(pluginResourceLocator, dependencyResolver, batchingConfiguration);
399         final Iterable<PluginResource> resourcesToInclude = builder.build(contexts, new ArrayList<String>(getIncludedContexts()), filter);
400         
401         final boolean batchingEnabled = batchingConfiguration.isSuperBatchingEnabled();
402         Set<String> moduleKeys = new HashSet<String>();
403 
404         for (final String skippedResource : builder.getSkippedResources())
405         {
406             Iterables.addAll(moduleKeys, toModuleKeys(dependencyResolver.getDependencies(skippedResource, batchingEnabled)));
407         }
408         
409         final Iterable<PluginResource> moduleResources = getModuleResources(moduleKeys, builder.getAllIncludedResources(), filter);
410         return writeResourceTags(concat(resourcesToInclude, moduleResources), new StringWriter(), urlMode).toString();        
411     }
412 
413     public String getStaticResourcePrefix(final String resourceCounter, final UrlMode urlMode)
414     {
415         return webResourceUrlProvider.getStaticResourcePrefix(resourceCounter, urlMode);
416     }
417 
418     public String getStaticPluginResource(final String moduleCompleteKey, final String resourceName, final UrlMode urlMode)
419     {
420         return webResourceUrlProvider.getStaticPluginResourceUrl(moduleCompleteKey, resourceName, urlMode);
421     }
422 
423     /**
424      * @return "{base url}/s/{build num}/{system counter}/{plugin version}/_/download/resources/{plugin.key:module.key}/{resource.name}"
425      */
426     public String getStaticPluginResource(final ModuleDescriptor<?> moduleDescriptor, final String resourceName, final UrlMode urlMode)
427     {
428         return webResourceUrlProvider.getStaticPluginResourceUrl(moduleDescriptor, resourceName, urlMode);
429     }
430 
431     public <T> T executeInNewContext(final Supplier<T> nestedExecution)
432     {
433         final Map<String, Object> cache = webResourceIntegration.getRequestCache();
434         final Map<String, Object> storedState = copyOf(cache);
435 
436         // clear the cache, as the nestedExecution must be executed in an empty environment
437         cache.clear();
438         try
439         {
440             return nestedExecution.get();
441         }
442         finally
443         {
444             // restore state, regardless of what happened
445             // we have to clear first to handle the following case:
446             //    nestedExecution wrote to the cache with a key that isn't in storedState. In this case we don't want
447             cache.clear();
448             cache.putAll(storedState);
449         }
450     }
451 
452     //
453     // private helpers
454     //
455 
456     private Iterable<PluginResource> getModuleResources(final Iterable<String> webResourcePluginModuleKeys, final Iterable<String> batchedModules, final WebResourceFilter filter)
457     {
458         final List<PluginResource> includedResources = new LinkedList<PluginResource>(); // use linked list as it gets removed from when writing
459         for (final String moduleKey : webResourcePluginModuleKeys)
460         {
461             if (contains(batchedModules, moduleKey))
462             {
463                 // skip this resource if it is already in a batch
464                 continue;
465             }
466 
467             final List<PluginResource> moduleResources = pluginResourceLocator.getPluginResources(moduleKey);
468             for (final PluginResource moduleResource : moduleResources)
469             {
470                 if (filter.matches(moduleResource.getResourceName()))
471                 {
472                     includedResources.add(moduleResource);
473                 }
474             }
475         }
476         return includedResources;
477     }
478 
479     private void writeContentAndSwallowErrors(final Writer writer, final String... contents)
480     {
481         try
482         {
483             for (final String content : contents)
484             {
485                 writer.write(content);
486             }
487         }
488         catch (final IOException ignore)
489         {}
490     }
491 
492     private LinkedHashSet<String> getIncludedContexts()
493     {
494         return getOrCreateFromRequestCache(REQUEST_CACHE_CONTEXT_KEY);
495     }
496 
497     private LinkedHashSet<String> getIncludedResourceNames()
498     {
499         return getOrCreateFromRequestCache(REQUEST_CACHE_RESOURCE_KEY);
500     }
501 
502     private LinkedHashSet<String> getOrCreateFromRequestCache(final String key)
503     {
504         final Map<String, Object> cache = webResourceIntegration.getRequestCache();
505         @SuppressWarnings("unchecked")
506         LinkedHashSet<String> set = (LinkedHashSet<String>) cache.get(key);
507         if (set == null)
508         {
509             set = Sets.newLinkedHashSet();
510             cache.put(key, set);
511         }
512         return set;
513     }
514 
515     private void clear()
516     {
517         getIncludedResourceNames().clear();
518         getIncludedContexts().clear();
519     }
520 
521     private Iterable<String> toModuleKeys(final Iterable<WebResourceModuleDescriptor> descriptors)
522     {
523         return transform(descriptors, new TransformDescriptorToKey());
524     }
525 
526     //
527     // deprecated impl to be removed in 3.0, only here for backwards compatibility not to be used
528     //
529 
530     @Deprecated
531     public String getRequiredResources()
532     {
533         return getRequiredResources(UrlMode.AUTO);
534     }
535 
536     @Deprecated
537     public String getResourceTags(final String moduleCompleteKey)
538     {
539         return getResourceTags(moduleCompleteKey, UrlMode.AUTO);
540     }
541 
542     @Deprecated
543     public String getStaticPluginResource(final ModuleDescriptor<?> moduleDescriptor, final String resourceName)
544     {
545         return getStaticPluginResource(moduleDescriptor, resourceName, UrlMode.AUTO);
546     }
547 
548     @Deprecated
549     public String getStaticPluginResource(final String moduleCompleteKey, final String resourceName)
550     {
551         return getStaticPluginResource(moduleCompleteKey, resourceName, UrlMode.AUTO);
552     }
553 
554     @Deprecated
555     public String getStaticPluginResourcePrefix(final ModuleDescriptor<?> moduleDescriptor, final String resourceName)
556     {
557         return getStaticPluginResource(moduleDescriptor, resourceName, UrlMode.AUTO);
558     }
559 
560     @Deprecated
561     public String getStaticResourcePrefix()
562     {
563         return webResourceUrlProvider.getStaticResourcePrefix(UrlMode.AUTO);
564     }
565 
566     @Deprecated
567     public String getStaticResourcePrefix(final UrlMode urlMode)
568     {
569         return webResourceUrlProvider.getStaticResourcePrefix(urlMode);
570     }
571 
572     @Deprecated
573     public String getStaticResourcePrefix(final String resourceCounter)
574     {
575         return getStaticResourcePrefix(resourceCounter, UrlMode.AUTO);
576     }
577 
578     @Deprecated
579     public void includeResources(final Writer writer)
580     {
581         includeResources(writer, UrlMode.AUTO);
582     }
583 
584     @Deprecated
585     public void requireResource(final String moduleCompleteKey, final Writer writer)
586     {
587         requireResource(moduleCompleteKey, writer, UrlMode.AUTO);
588     }
589 
590     @Deprecated
591     public void setIncludeMode(final IncludeMode includeMode)
592     {
593         webResourceIntegration.getRequestCache().put("plugin.webresource.mode", includeMode);
594     }
595 }