KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > google > gwt > dev > util > SelectionScriptGenerator


1 /*
2  * Copyright 2007 Google Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5  * use this file except in compliance with the License. You may obtain a copy of
6  * the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13  * License for the specific language governing permissions and limitations under
14  * the License.
15  */

16 package com.google.gwt.dev.util;
17
18 import com.google.gwt.dev.cfg.ModuleDef;
19 import com.google.gwt.dev.cfg.Properties;
20 import com.google.gwt.dev.cfg.Property;
21 import com.google.gwt.dev.cfg.PropertyProvider;
22 import com.google.gwt.dev.cfg.Script;
23 import com.google.gwt.dev.cfg.Scripts;
24 import com.google.gwt.dev.cfg.Styles;
25 import com.google.gwt.dev.js.JsObfuscateNamer;
26 import com.google.gwt.dev.js.JsParser;
27 import com.google.gwt.dev.js.JsParserException;
28 import com.google.gwt.dev.js.JsSourceGenerationVisitor;
29 import com.google.gwt.dev.js.JsSymbolResolver;
30 import com.google.gwt.dev.js.JsVerboseNamer;
31 import com.google.gwt.dev.js.ast.JsName;
32 import com.google.gwt.dev.js.ast.JsProgram;
33 import com.google.gwt.dev.js.ast.JsScope;
34 import com.google.gwt.util.tools.Utility;
35
36 import java.io.IOException JavaDoc;
37 import java.io.PrintWriter JavaDoc;
38 import java.io.Reader JavaDoc;
39 import java.io.StringReader JavaDoc;
40 import java.io.StringWriter JavaDoc;
41 import java.net.MalformedURLException JavaDoc;
42 import java.net.URL JavaDoc;
43 import java.util.HashSet JavaDoc;
44 import java.util.Iterator JavaDoc;
45 import java.util.Map JavaDoc;
46 import java.util.Set JavaDoc;
47 import java.util.TreeMap JavaDoc;
48 import java.util.Map.Entry;
49
50 /**
51  * Generates the "module.nocache.html" file for use in both hosted and web mode.
52  * It is able to generate JavaScript with the knowledge of a module's settings.
53  * This class is used by {@link com.google.gwt.dev.GWTCompiler} and
54  * {@link com.google.gwt.dev.shell.GWTShellServlet}.
55  */

56 public class SelectionScriptGenerator {
57
58   private static String JavaDoc cssInjector(String JavaDoc cssUrl) {
59     if (isRelativeURL(cssUrl)) {
60       return " if (!__gwt_stylesLoaded['"
61           + cssUrl
62           + "']) {\n"
63           + " __gwt_stylesLoaded['"
64           + cssUrl
65           + "'] = true;\n"
66           + " document.write('<link rel=\\\"stylesheet\\\" HREF=\\\"'+base+'"
67           + cssUrl + "\\\">');\n" + " }\n";
68     } else {
69       return " if (!__gwt_stylesLoaded['" + cssUrl + "']) {\n"
70           + " __gwt_stylesLoaded['" + cssUrl + "'] = true;\n"
71           + " document.write('<link rel=\\\"stylesheet\\\" HREF=\\\""
72           + cssUrl + "\\\">');\n" + " }\n";
73     }
74   }
75
76   /**
77    * Determines whether or not the URL is relative.
78    *
79    * @param src the test url
80    * @return <code>true</code> if the URL is relative, <code>false</code> if
81    * not
82    */

83   private static boolean isRelativeURL(String JavaDoc src) {
84     // A straight absolute url for the same domain, server, and protocol.
85
if (src.startsWith("/")) {
86       return false;
87     }
88
89     // If it can be parsed as a URL, then it's probably absolute.
90
try {
91       URL JavaDoc testUrl = new URL JavaDoc(src);
92
93       // Let's guess that it is absolute (thus, not relative).
94
return false;
95     } catch (MalformedURLException JavaDoc e) {
96       // Do nothing, since it was a speculative parse.
97
}
98
99     // Since none of the above matched, let's guess that it's relative.
100
return true;
101   }
102
103   private static String JavaDoc literal(String JavaDoc lit) {
104     return "\"" + lit + "\"";
105   }
106
107   private static void replaceAll(StringBuffer JavaDoc buf, String JavaDoc search, String JavaDoc replace) {
108     int len = search.length();
109     for (int pos = buf.indexOf(search); pos >= 0; pos = buf.indexOf(search,
110         pos + 1)) {
111       buf.replace(pos, pos + len, replace);
112     }
113   }
114
115   private static String JavaDoc scriptInjector(String JavaDoc scriptUrl) {
116     if (isRelativeURL(scriptUrl)) {
117       return " if (!__gwt_scriptsLoaded['"
118           + scriptUrl
119           + "']) {\n"
120           + " __gwt_scriptsLoaded['"
121           + scriptUrl
122           + "'] = true;\n"
123           + " document.write('<script language=\\\"javascript\\\" SRC=\\\"'+base+'"
124           + scriptUrl + "\\\"></script>');\n" + " }\n";
125     } else {
126       return " if (!__gwt_scriptsLoaded['" + scriptUrl + "']) {\n"
127           + " __gwt_scriptsLoaded['" + scriptUrl + "'] = true;\n"
128           + " document.write('<script language=\\\"javascript\\\" SRC=\\\""
129           + scriptUrl + "\\\"></script>');\n" + " }\n";
130     }
131   }
132
133   private final String JavaDoc moduleFunction;
134   private final String JavaDoc moduleName;
135   private final Properties moduleProps;
136   private final Property[] orderedProps;
137
138   /**
139    * Maps compilation strong name onto a <code>Set</code> of
140    * <code>String[]</code>. We use a <code>TreeMap</code> to produce the
141    * same generated code for the same set of compilations.
142    */

143   private final Map JavaDoc propertyValuesSetByStrongName = new TreeMap JavaDoc();
144   private final Scripts scripts;
145   private final Styles styles;
146
147   /**
148    * A constructor for creating a selection script that will work only in hosted
149    * mode.
150    *
151    * @param moduleDef the module for which the selection script will be
152    * generated
153    */

154   public SelectionScriptGenerator(ModuleDef moduleDef) {
155     this.moduleName = moduleDef.getName();
156     this.moduleFunction = moduleDef.getFunctionName();
157     this.scripts = moduleDef.getScripts();
158     this.styles = moduleDef.getStyles();
159     this.moduleProps = moduleDef.getProperties();
160     this.orderedProps = null;
161   }
162
163   /**
164    * A constructor for creating a selection script that will work in either
165    * hosted or web mode.
166    *
167    * @param moduleDef the module for which the selection script will be
168    * generated
169    * @param props the module's property objects, arranged in the same order in
170    * which sets of property values should be interpreted by the
171    * {@link #recordSelection(String[], String)} method
172    */

173   public SelectionScriptGenerator(ModuleDef moduleDef, Property[] props) {
174     this.moduleName = moduleDef.getName();
175     this.moduleFunction = moduleName.replace('.', '_');
176     this.scripts = moduleDef.getScripts();
177     this.styles = moduleDef.getStyles();
178     this.moduleProps = moduleDef.getProperties();
179     this.orderedProps = (Property[]) props.clone();
180   }
181
182   /**
183    * Generates a selection script based on the current settings.
184    *
185    * @return an JavaScript whose contents are the definition of a module.js file
186    */

187   public String JavaDoc generateSelectionScript(boolean obfuscate, boolean asScript) {
188     try {
189       String JavaDoc rawSource;
190       {
191         StringWriter JavaDoc sw = new StringWriter JavaDoc();
192         PrintWriter JavaDoc pw = new PrintWriter JavaDoc(sw, true);
193
194         String JavaDoc template = Utility.getFileFromClassPath(asScript
195             ? "com/google/gwt/dev/util/SelectionScriptTemplate-xs.js"
196             : "com/google/gwt/dev/util/SelectionScriptTemplate.js");
197         genScript(pw, template);
198
199         pw.close();
200         rawSource = sw.toString();
201       }
202
203       {
204         JsParser parser = new JsParser();
205         Reader JavaDoc r = new StringReader JavaDoc(rawSource);
206         JsProgram jsProgram = new JsProgram();
207         JsScope topScope = jsProgram.getScope();
208         JsName funcName = topScope.declareName(moduleFunction);
209         funcName.setObfuscatable(false);
210
211         parser.parseInto(topScope, jsProgram.getGlobalBlock(), r, 1);
212         JsSymbolResolver.exec(jsProgram);
213         if (obfuscate) {
214           JsObfuscateNamer.exec(jsProgram);
215         } else {
216           JsVerboseNamer.exec(jsProgram);
217         }
218
219         DefaultTextOutput out = new DefaultTextOutput(obfuscate);
220         JsSourceGenerationVisitor v = new JsSourceGenerationVisitor(out);
221         v.accept(jsProgram);
222         return out.toString();
223       }
224     } catch (IOException JavaDoc e) {
225       throw new RuntimeException JavaDoc("Error processing selection script template.",
226           e);
227     } catch (JsParserException e) {
228       throw new RuntimeException JavaDoc("Error processing selection script template.",
229           e);
230     }
231   }
232
233   /**
234    * Records a mapping from a unique set of client property values onto a strong
235    * name (that is, a compilation).
236    *
237    * @param values a set of client property values ordered such that the i'th
238    * value corresponds with the i'th property in {@link #props}
239    * @param strongName the base name of a compiled <code>.cache.html</code>
240    * file
241    */

242   public void recordSelection(String JavaDoc[] values, String JavaDoc strongName) {
243     Set JavaDoc valuesSet = (Set JavaDoc) propertyValuesSetByStrongName.get(strongName);
244     if (valuesSet == null) {
245       valuesSet = new HashSet JavaDoc();
246       propertyValuesSetByStrongName.put(strongName, valuesSet);
247     }
248     valuesSet.add(values.clone());
249   }
250
251   private void genAnswers(PrintWriter JavaDoc pw) {
252     for (Iterator JavaDoc iter = propertyValuesSetByStrongName.entrySet().iterator(); iter.hasNext();) {
253       Map.Entry JavaDoc entry = (Entry) iter.next();
254       String JavaDoc strongName = (String JavaDoc) entry.getKey();
255       Set JavaDoc propValuesSet = (Set JavaDoc) entry.getValue();
256
257       // Create one answers entry for each string array in the set.
258
//
259
for (Iterator JavaDoc iterator = propValuesSet.iterator(); iterator.hasNext();) {
260         String JavaDoc[] propValues = (String JavaDoc[]) iterator.next();
261
262         pw.print(" unflattenKeylistIntoAnswers([");
263         boolean firstPrint = true;
264         for (int i = 0; i < orderedProps.length; i++) {
265           Property prop = orderedProps[i];
266           String JavaDoc activeValue = prop.getActiveValue();
267           if (activeValue == null) {
268             // This is a call to a property provider function; we need it to
269
// select the script.
270
//
271
if (!firstPrint) {
272               pw.print(",");
273             }
274             firstPrint = false;
275             pw.print(literal(propValues[i]));
276           } else {
277             // This property was explicitly set at compile-time; we do not need
278
// it.
279
}
280         }
281         pw.print("]");
282         pw.print(",");
283         pw.print(literal(strongName));
284         pw.println(");");
285       }
286     }
287   }
288
289   private void genPropProviders(PrintWriter JavaDoc pw) {
290     for (Iterator JavaDoc iter = moduleProps.iterator(); iter.hasNext();) {
291       Property prop = (Property) iter.next();
292       String JavaDoc activeValue = prop.getActiveValue();
293       if (activeValue == null) {
294         // Emit a provider function, defined by the user in module config.
295
PropertyProvider provider = prop.getProvider();
296         assert (provider != null) : "expecting a default property provider to have been set";
297         String JavaDoc js = provider.getBody().toSource();
298         pw.print("providers['" + prop.getName() + "'] = function() ");
299         pw.print(js);
300         pw.println(";");
301
302         // Emit a map of allowed property values as an object literal.
303
pw.println();
304         pw.println("values['" + prop.getName() + "'] = {");
305         String JavaDoc[] knownValues = prop.getKnownValues();
306         for (int i = 0; i < knownValues.length; i++) {
307           if (i > 0) {
308             pw.println(", ");
309           }
310           // Each entry is of the form: "propName":<index>.
311
// Note that we depend here on the known values being already
312
// enclosed in quotes (because property names can have dots which
313
// aren't allowed unquoted as keys in the object literal).
314
pw.print(literal(knownValues[i]) + ": ");
315           pw.print(i);
316         }
317         pw.println();
318         pw.println("};");
319       }
320     }
321   }
322
323   private void genPropValues(PrintWriter JavaDoc pw) {
324     for (int i = 0; i < orderedProps.length; i++) {
325       Property prop = orderedProps[i];
326       String JavaDoc activeValue = prop.getActiveValue();
327       if (activeValue == null) {
328         // This is a call to a property provider function; we need it to
329
// select the script.
330
//
331
PropertyProvider provider = prop.getProvider();
332         assert (provider != null) : "expecting a default property provider to have been set";
333         // When we call the provider, we supply a bogus argument to indicate
334
// that it should throw an exception if the property is a bad value.
335
// The absence of arguments (as in hosted mode) tells it to return null.
336
pw.print("[");
337         pw.print("computePropValue('" + prop.getName() + "')");
338         pw.print("]");
339       } else {
340         // This property was explicitly set at compile-time; we do not need it.
341
}
342     }
343   }
344
345   /**
346    * Emits all the script required to set up the module and, in web mode, select
347    * a compilation.
348    *
349    * @param pw
350    */

351   private void genScript(PrintWriter JavaDoc mainPw, String JavaDoc template) {
352     StringBuffer JavaDoc buf = new StringBuffer JavaDoc(template);
353     replaceAll(buf, "__MODULE_FUNC__", moduleFunction);
354     replaceAll(buf, "__MODULE_NAME__", moduleName);
355
356     if (orderedProps != null) {
357       // Remove shell servlet only stuff (hosted mode support)
358
int startPos = buf.indexOf("// __SHELL_SERVLET_ONLY_BEGIN__");
359       int endPos = buf.indexOf("// __SHELL_SERVLET_ONLY_END__");
360       buf.delete(startPos, endPos);
361     }
362
363     // Add external dependencies
364
int startPos = buf.indexOf("// __MODULE_DEPS_END__");
365     for (Iterator JavaDoc iter = styles.iterator(); iter.hasNext();) {
366       String JavaDoc style = (String JavaDoc) iter.next();
367       String JavaDoc text = cssInjector(style);
368       buf.insert(startPos, text);
369       startPos += text.length();
370     }
371
372     for (Iterator JavaDoc iter = scripts.iterator(); iter.hasNext();) {
373       Script script = (Script) iter.next();
374       String JavaDoc text = scriptInjector(script.getSrc());
375       buf.insert(startPos, text);
376       startPos += text.length();
377     }
378
379     // Add property providers
380
{
381       StringWriter JavaDoc sw = new StringWriter JavaDoc();
382       PrintWriter JavaDoc pw = new PrintWriter JavaDoc(sw, true);
383       genPropProviders(pw);
384       pw.close();
385       String JavaDoc stuff = sw.toString();
386       startPos = buf.indexOf("// __PROPERTIES_END__");
387       buf.insert(startPos, stuff);
388     }
389
390     // Add permutations
391
{
392       StringWriter JavaDoc sw = new StringWriter JavaDoc();
393       PrintWriter JavaDoc pw = new PrintWriter JavaDoc(sw, true);
394
395       // If the ordered props are specified, then we're generating for both
396
// modes.
397
if (orderedProps != null) {
398         // Determine if there's only one possible answer.
399
if (propertyValuesSetByStrongName.size() > 1) {
400           // Multiple answers; generate computations.
401
pw.println();
402           genAnswers(pw);
403           pw.println();
404           pw.print(" strongName = answers");
405           genPropValues(pw);
406         } else {
407           // Only one answer; explicit properties set or rare cases.
408
Set JavaDoc entrySet = propertyValuesSetByStrongName.entrySet();
409           assert (entrySet.size() == 1);
410           Map.Entry JavaDoc entry = (Entry) entrySet.iterator().next();
411           String JavaDoc strongName = (String JavaDoc) entry.getKey();
412           // Just use a literal for the single answer.
413
pw.print(" strongName = " + literal(strongName));
414         }
415         pw.println(";");
416       }
417
418       pw.close();
419       String JavaDoc stuff = sw.toString();
420       startPos = buf.indexOf("// __PERMUTATIONS_END__");
421       buf.insert(startPos, stuff);
422     }
423
424     mainPw.print(buf.toString());
425   }
426
427 }
428
Popular Tags