#summary This document describes how GWT chooses resources.
== Introduction ==
GWT models pretty much everything as a resource. A resource might be a java source file, a class file, an html file, or a jar file. This design document describes how GWT determines which resources to include in a module.
== Glossary ==
==={{{ClassPathEntry}}}===
A {{{ClassPathEntry}}} represents a single entry on the Java system classpath at startup. These entries generally are either file system directory trees ({{{DirectoryClassPathEntry}}}) or jar/zip files ({{{ZipFileClassPathEntry}}}).
==={{{PathPrefix}}}===
A {{{PathPrefix}}} provides the ability to select resources based on
their path names. For example, {{{PathPrefix("a/b")}}} only allows resource with path names that begin with a/b. A {{{PathPrefix}}} can select resources in a more general way by specifying a {{{ResourceFilter}}} and implementing its {{{allows}}} method. Finally, a {{{PathPrefix}}} also allows for rerooting of resources whereby the path of the resource is shortened.
==={{{PathPrefixSet}}}===
A {{{PathPrefixSet}}} is a collection of {{{PathPrefix}}}. Note that if two or more {{{PathPrefix}}} with the same prefix but different resource filters are added to a {{{PathPrefixSet}}}, only the last one is kept.
==={{{Resource}}}===
A {{{Resource}}} is any file that GWT uses.
==Determining the resources a GWT module includes==
Conceptually, this determination is a three step process.
===Step 1: Construct the list of {{{ClassPathEntry}}} and the {{{PathPrefixSet}}} for a module===
The resources included by a GWT module depends mainly on two things:
# {{{ClassPathEntry}}}: The order in which the {{{ClassPathEntry}}} are specified is important. This order is solely determined by the order in which entries are specified on the java classpath.
# {{{PathPrefixSet}}}: The order in which various {{{PathPrefix}}} were added to the {{{PathPrefixSet}}} is important. This order is determined by traversing the module inheritance tree rooted at the entry-point module in the lexical order. Plus, whether or not a {{{PathPrefix}}} causes its resources to be rerooted is important. Note that a {{{PathPrefix}}} with a source tag is not re-rooted but {{{PathPrefix}}} with public and super-src tags are re-rooted. For example, if the modules are as follows:
{{{
Module MyApp.gwt.xml:
Module User.gwt.xml:
Module Dev.gwt.xml:
}}}
the {{{PathPrefixSet}}} constructed is as follows. Think of the modules being inlined to determine the lexical ordering of the {{{PathPrefix}}}.
{{{
PathPrefixSet pps = new PathPrefixSet();
p1 = new PathPrefix(""); // From module User.gwt.xml
p2 = new PathPrefix("a/", WITH_REROOTING); // From module Dev.gwt.xml
p3 = new PathPrefix("a/b/", filter allows only *.java); // From module MyApp.gwt.xml
pps.add(p1);
pps.add(p2);
pps.add(p3);
}}}
===Step 2: Determine the bag of resources for the list of {{{ClassPathEntry}}} and {{{PathPrefixSet}}}===
For each {{{ClassPathEntry}}}, there is a deterministic collection of resources that is allowed by a {{{PathPrefixSet}}}. Specifically, each {{{Resource}}} matches a unique {{{PathPrefix}}} in a {{{PathPrefixSet}}}. The resource is allowed if the filter of the matching {{{PathPrefix}}} allows the resource. Lastly, the path of each allowed resource is computed. A resource is either a rerooted resource or a normal resource, depending on whether the {{{PathPrefix}}} that allows it requires rerooting or not. A rerooted resource's path is its path name following the {{{ClassPathEntry}}} and the {{{PathPrefix}}}. A normal resource's path is its name following the {{{ClassPathEntry}}}. In the example below, resources {{{r2}}} and {{{r5}}} match {{{PathPrefix}}} {{{p2}}}. Therefore, their (rerooted) path is "Test.java" and "a/b/Test.java" respectively.
{{{
Initial path Matching PathPrefix allowed Path
r1 Test.java p1 yes Test.java
r2 a/Test.java p2 yes Test.java (rerooted)
r3 a/b/Test.java p3 yes a/b/Test.java
r4 a/b/gwt.gif p3 No n/a
r5 a/a/b/Test.java p2 yes a/b/Test.java (rerooted)
}}}
===Step 3: Determine which resource to include for each unique path===
From this collection of resources, where each resource has an associated {{{PathPrefix}}}, {{{ClassPathEntry}}}, and a path, one resource is selected for each unique path. If there are multiple resources for a path, the following tie-breaker rules are used:
# A rerooted resource is preferred over a non-rerooted resource.
# A resource with a matching {{{PathPrefix}}} that was added to the {{{PathPrefixSet}}} later is preferred over a resource with a matching {{{PathPrefix}}} that was added earlier to the {{{PathPrefixSet}}}.
# A resource with earlier {{{ClassPathEntry}}} is preferred over a resource with a later {{{ClassPathEntry}}}.
These rules are ordered. Thus, a rerooted resource is always preferred over a non-rerooted resource, no matter how their matching {{{PathPrefix}}} and {{{ClassPathEntry}}} compare. To continue with the above example, the final resource map is:
{{{
Test.java => r2
a/b/Test.java => r5
}}}
because resource {{{r2}}} shadows {{{r1}}} and resource {{{r5}}} shadows {{{r3}}}. The examples above did not involve a tie-breaker rule involving {{{ClassPathEntry}}}, but it is easy to see how it would be used.
==Steps taken during a refresh==
A {{{ResourceOracleImpl}}} refresh maintains the following invariants:
# If no resources change during the refresh, the identities of all the Collections exposed by the {{{ResourceOracleImpl}}} remains the same.
# If any of the previous resource does not change during the refresh, its identity remains the same.
During a refresh, as a first step, the resource map is recomputed. If none of the resources in the map have changed, the previous collections are kept as is. This guarantees invariant 1. Furthermore, if a resource has not changed, the old resource is used instead of the new resource, thus guaranteeing invariant 2.
==When multiple {{{PathPrefix}}}es have the same path==
_(Note: As of Gwt 1.6, this section has not been implemented)_
As of Gwt 1.6, if multiple {{{PathPrefix}}}es have the same path attribute but different {{{ResourceFilter}}}s, only the last one is kept. This is an undesirable outcome in most cases. For example, if there are two {{{PathPrefix}}}es p4 and p5:
{{{
p4:
p5:
}}}
only the second path-prefix (p5) is kept. In particular, a path like client/Bar.java is excluded, as a result of being excluded by the second path-prefix. This outcome is probably different from what the user expects. In this scenario, any path-prefixes defined by a user, however specific, could end up clobbering any path-prefixes that the user's modules inherit. The primary reason this clobbering happens is because Gwt 1.6 internally does not distinguish between the inclusion (exclusion) being specifically mentioned by the {{{PathPrefix}}} and the inclusion (exclusion) due to defaults. When a resource with a specified path is processed by a Gwt 1.6 {{{PathPrefix}}}, the output is either *include* or *exclude*. The resource is included if the output is *include*. Else, the output is *exclude* and the resource is excluded. To handle multiple {{{PathPrefix}}}es meaningfully, we generalize the output to be:
# *include*: if the include filter of the {{{PathPrefix}}} specifically includes the resource and its exclude filter does not excludes the resource.
# *exclude*: if the exclude filter of the {{{PathPrefix}}} specifically excludes the resource.
# *unspecified_include*: if the resource is included just by default. For example, a path-prefix {{{}}} includes all java files in the client directory by default.
# *unspecified_exclude*: if none of the above three outputs apply. For example, a path-prefix {{{}}} excludes a file with path as {{{client/Bar.java}}} by default.
For each path-prefix path, an ordered list of {{{PathPrefix}}}es is maintained, with the lexically last {{{PathPrefix}}} at the head of the list. If a resource matches a {{{PathPrefix}}} path, path-prefixes are applied from the ordered list starting from the head. The next {{{PathPrefix}}} in the list is applied only if the previous path-prefix filter's output is either *unspecified_include* or *unspecified_exclude*. If the output remains *unspecified_include* (*unspecified_exclude*) at the end, it is treated as an *include* (*exclude*). As with Gwt 1.6, the resource is included if the output is *include* at the end. Else, the output is *exclude* and it is excluded.
This algorithm is just a generalization of Gwt 1.6's resource filtering algorithm. It should not be a breaking change except in a few edge cases relying on inclusion or exclusion by default.