0

I need to precisely specify GWT permutations and control the variation within them (combinations of property values supported by each) but have hard time finding detailed behaviour specification.

During my experimentation I have learned that I have to watch for creating set-property ... when-property-is cycles even though these cycles are "stable" - i.e. they do not change any part of the cycle, just "confirm" it. That restricted what I can do, so I decided to try another way - define a brand new property, (just) for example:

  <define-property name="precise.permutation" values="webkit,gecko,ie,unsupported"/>

... and then have something like:

  <set-property name="precise.permutation" value="webkit">
    <!-- ... custom conditions ... -->
  </set-property>
  <set-property name="precise.permutation" value="gecko">
    <!-- ... custom conditions ... -->
  </set-property>
  <set-property name="precise.permutation" value="ie">
    <!-- ... custom conditions ... -->
  </set>
  <set-property name="precise.permutation" value="unsupported">
    <!-- ... custom conditions ... -->
  </set-property>

... I then tried restricting this to all but unsupported which is used as an example but is entirely counter-intuitive as it uses the same set-property tag as above:

  <set-property name="precise.permutation" value="webkit,gecko,ie" />

I also had to collapse other properties to make sure that they don't cause additional permutations.

Unfortunately, that does not seem to work as intended (tried with GWT 2.8 RC2). Even though the "unsupported" permutation does not show up (this is desired), the combinations of properties from it reappear in other permutations (which isn't desired).

Can someone help me find authoritative and complete documentation on this or help me figure this out, please?

Thanks!

Learner
  • 1,215
  • 1
  • 11
  • 26
  • Can you outline the specifics of what you are after? Such as what "custom conditions" are, and what the outcome is expected to be (versus what it is)? Assuming you have one-to-many OR'd conditions in each one, then you _should_ be getting multiple permutations per `precise.permutation`, since you haven't defined any collapsing (at least not that you've shared). Without specifics, we can't see what you don't understand. – Colin Alworth Sep 13 '16 at 03:40
  • That is, exactly what have you tried, what did you expect, and what did you get instead? From that we can either tell you what you failed to account for (and how to fix it or phrase it differently), or file a bug that you've discovered (and perhaps tell you how to work around it). – Colin Alworth Sep 13 '16 at 03:43
  • My problem is that I don't know what *.gwt.xml constructs do exactly as they aren't precisely defined anywhere. Thus, I can't really form any expectations - I am just poking in the dark. Trying to figure out how to both directly control permutations and reduce their internal complexity too - I don't need some cases supported at all, esp. within some of the permutations.. – Learner Sep 13 '16 at 03:47
  • The short version is that the permutations consist of the cross-product of all values of all properties. Through the use of an unconditional ``, you can reduce the values that are possible globally, and conditional tags let you ensure a certain value for that property only in _that_ specific case. Collapse rules are like unconditional rules, since they reduce the possible number of values. That really is it - the rules may appear simple (or can be concisely written), but there are no more rules, its just how literally those rules must be followed. Any longer needs an example. – Colin Alworth Sep 13 '16 at 03:56
  • But how are they evaluated? Once, in order, or are they, in some way, event based and can be triggered at any time, in any order? What does really do, as it is used to fix a value to one, limit the possible values to some and also be conditional? Can I conditionally set it to multiple values, for example? – Learner Sep 13 '16 at 04:02
  • They are evaluated all at once, effectively at the beginning of the compiler, to discover how much work there is to do. Any property providers (not discussed so far) are evaluated at runtime in JS to decide which already-existing permutation to use, including which "Soft" permutation within that permutation (but doesn't really apply, since there aren't actually permutations). Order only matters insofar as a later set-property can reassign an earlier one, but its just multiplication otherwise. SO isn't a chat app - either post a concrete example and question, or move to mailing list or irc. – Colin Alworth Sep 13 '16 at 04:07
  • I just did some more experimenting on this and believe that now I understand. It is a bit of a mess in there as names are incorrect (permutations aren't *permutations*), and set-property actually overrides the collection of values, etc. Will try to answer this below. – Learner Sep 13 '16 at 04:22

1 Answers1

2

I still have't found the detailed documentation but I have done a ton of experimentation and have concluded the following...

(Note: my examples use some concepts from Sencha GXT which I develop with)

<define-property> is used to define the property and its possible values but is not the last word in terms of which values will be actually used. There should be exactly one such definition per property in the hierarchy of the *.gwt.xml files.

<set-property> does NOT set the property to A value but creates a sort of a rule with the COLLECTION of POSSIBLE values for that property (ideally to a subset of what is defined in &ltdefine-property>). The last declaration of <set-property> for a given property wins. Be careful! If you use a <set-property> after <inherits> (inheriting a module), you may/will be overriding any rules that you inherited. Note that there are conditional rules and unconditional rules. For example,

<set-property name="gxt.user.agent" value="ie10, ie11, gecko1_9, safari5, chrome"/>

... will unconditionally state that, when determining permutations, the property 'gxt.user.agent' can have any one of the listed values. Conversely,

<set-property name="user.agent" value="safari">
  <any>
    <when-property-is name="gxt.user.agent" value="safari5" />
    <when-property-is name="gxt.user.agent" value="chrome" />
  </any>
</set-property>

Will state that user.agent can only be "safari" when "gxt.user.agent" is either "safari5" or "chrome". The order seems important, so you would want rules for dependent properties declared after the rules for their dependencies. Cyclic dependencies will fail the compilation. You can create many conditional rules as long as they don't contradict one another. I do not know yet what would happen if they do, but I guess that the last declared would win.

Note that the conditional rules can also specify multiple possible values. For example (illustration only, may not match your needs):

<!-- On desktops we do all browsers including IE -->
<set-property name="gxt.user.agent" value="safari5, chrome, gecko1_9, ie11">
  <when-property-is name="gxt.device" value="desktop" />
</set-property>
<!-- ... but on tablets and phones we exclude IE -->
<set-property name="gxt.user.agent" value="safari5, chrome, gecko1_9">
  <any>
    <when-property-is name="gxt.device" value="tablet" />
    <when-property-is name="gxt.device" value="phone" />
  </any>
</set-property>

You can use <any> and <all> to create complex/compound criteria. These can be nested inside one another.

How can this be used to get precise control of permutations? You may not need this but it helped me to begin by defining two properties like these:

<define-property name="custom.use.case" values="case1, case2, ..."/>
<property-provider name="helix.product.mode"><![CDATA[   
    var useCase = ...; // JavaScript code to determine the use case
    return useCase;
  ]]>
</property-provider>
<define-property name="custom.permutation" values="perm1, perm2, ..."/>

The first property defines the use case. Above I have a way to determine it at runtime. You may not and may skip it. It also serves as a starting point to define everything else as we can define all the other properties based on the use case. For example:

<!-- Case 1 restrictions -->
<set-property name="gxt.device" value="desktop">
  <when-property-is name="custom.use.case" value="case1" />
</set-property>
<set-property name="gxt.user.agent" value="chrome, safari5, gecko1_9, ie11">
  <when-property-is name="custom.use.case" value="case1" />
</set-property>
...

<!-- Case 2 restrictions -->
<set-property name="gxt.device" value="tablet, phone">
  <when-property-is name="custom.use.case" value="case2" />
</set-property>
<set-property name="gxt.user.agent" value="chrome, safari5, gecko1_9">
  <when-property-is name="custom.use.case" value="case2" />
</set-property>
...

<!-- Case 3 restrictions -->
<set-property name="gxt.device" value="tablet, phone">
  <when-property-is name="custom.use.case" value="case3" />
</set-property>
<set-property name="gxt.user.agent" value="safari5">
  <when-property-is name="custom.use.case" value="case3" />
</set-property>
...

etc.

Next thing to do is to collapse all the properties except for the custom.permutation, because we only want custom.permutation to drive the permutations:

  <collapse-property name="custom.use.case" values="*" />  
  <collapse-property name="gxt.device" values="*" />
  <collapse-property name="gxt.user.agent" values="*" />
  <collapse-property name="user.agent" values="*" />
  <collapse-property name="user.agent.os" values="*" />

This approach allows extremely fine grain control over "permutations" and their internal complexity, the "soft permutations" as some call them. There will be exactly one permutation for each possible "custom.permutation" property value. Each permutation will only have the needed "soft permutations" in it if you do a good job of setting up the rules above.

Note that both actual and soft permutations cost. Having many soft permutations (grouped into actual permutations or not) costs compile performance and runtime code size of the permutation they are grouped in. Do not ignore this, especially if you have many properties. Actual permutations have even higher compile and linking time cost (but having more of them as opposed to combining many soft permutations into grouped actual permutations reduces the size of each permutation).

If using GXT, starting with version 4, you will notice that it adds gxt.device property having the values such as desktop, tablet and phone. This caused our compilation time to increase about 6-7 times after upgrading to GXT 4 because our permutations went out of control. Some ended up being, quite literally, made for Internet Explorer running on a Mac OS tablet. You can appreciate what a waste of time permutations for non-existent use cases are. By implementing the above we were able to reduce the GWT compilation time down to about half of the original time or about 10-12 times faster than what they were right after GXT 4 upgrade.

Learner
  • 1,215
  • 1
  • 11
  • 26