KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > google > gwt > dev > cfg > ModuleDef


1 /*
2  * Copyright 2006 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.cfg;
17
18 import com.google.gwt.core.ext.TreeLogger;
19 import com.google.gwt.core.ext.UnableToCompleteException;
20 import com.google.gwt.core.ext.typeinfo.CompilationUnitProvider;
21 import com.google.gwt.core.ext.typeinfo.TypeOracle;
22 import com.google.gwt.dev.jdt.CacheManager;
23 import com.google.gwt.dev.jdt.TypeOracleBuilder;
24 import com.google.gwt.dev.jdt.URLCompilationUnitProvider;
25 import com.google.gwt.dev.util.Empty;
26 import com.google.gwt.dev.util.FileOracle;
27 import com.google.gwt.dev.util.FileOracleFactory;
28 import com.google.gwt.dev.util.Util;
29 import com.google.gwt.dev.util.FileOracleFactory.FileFilter;
30
31 import org.apache.tools.ant.types.ZipScanner;
32
33 import java.io.File JavaDoc;
34 import java.net.URL JavaDoc;
35 import java.util.ArrayList JavaDoc;
36 import java.util.Arrays JavaDoc;
37 import java.util.Comparator JavaDoc;
38 import java.util.HashMap JavaDoc;
39 import java.util.HashSet JavaDoc;
40 import java.util.Iterator JavaDoc;
41 import java.util.List JavaDoc;
42 import java.util.Map JavaDoc;
43 import java.util.Set JavaDoc;
44 import java.util.Map.Entry;
45
46 /**
47  * Represents a module specification. In principle, this could be built without
48  * XML for unit tests.
49  */

50 public class ModuleDef {
51
52   private static final FileFilter JAVA_ACCEPTOR = new FileFilter() {
53     public boolean accept(String JavaDoc name) {
54       return name.endsWith(".java");
55     }
56   };
57
58   private static final Comparator JavaDoc REV_NAME_CMP = new Comparator JavaDoc() {
59     public int compare(Object JavaDoc o1, Object JavaDoc o2) {
60       Map.Entry JavaDoc entry1 = (Entry) o1;
61       Map.Entry JavaDoc entry2 = (Entry) o2;
62       String JavaDoc key1 = (String JavaDoc) entry1.getKey();
63       String JavaDoc key2 = (String JavaDoc) entry2.getKey();
64       // intentionally reversed
65
return key2.compareTo(key1);
66     }
67   };
68
69   public static boolean isValidModuleName(String JavaDoc moduleName) {
70     String JavaDoc[] parts = moduleName.split("\\.");
71     for (int i = 0; i < parts.length; i++) {
72       String JavaDoc part = parts[i];
73       if (!Util.isValidJavaIdent(part)) {
74         return false;
75       }
76     }
77     return true;
78   }
79
80   private final ArrayList JavaDoc allCups = new ArrayList JavaDoc();
81
82   private final Set JavaDoc alreadySeenFiles = new HashSet JavaDoc();
83
84   private final CacheManager cacheManager = new CacheManager(".gwt-cache",
85       new TypeOracle());
86
87   private CompilationUnitProvider[] cups = new CompilationUnitProvider[0];
88
89   private final List JavaDoc entryPointTypeNames = new ArrayList JavaDoc();
90
91   private final Set JavaDoc gwtXmlFiles = new HashSet JavaDoc();
92
93   private FileOracle lazyPublicOracle;
94
95   private FileOracle lazySourceOracle;
96
97   private TypeOracle lazyTypeOracle;
98
99   private final long moduleDefCreationTime = System.currentTimeMillis();
100
101   private final String JavaDoc name;
102
103   private final Properties properties = new Properties();
104
105   private final FileOracleFactory publicPathEntries = new FileOracleFactory();
106
107   private final Rules rules = new Rules();
108
109   private final Scripts scripts = new Scripts();
110
111   private final Map JavaDoc servletClassNamesByPath = new HashMap JavaDoc();
112
113   private final FileOracleFactory sourcePathEntries = new FileOracleFactory();
114
115   private final Styles styles = new Styles();
116
117   public ModuleDef(String JavaDoc name) {
118     this.name = name;
119   }
120
121   public synchronized void addEntryPointTypeName(String JavaDoc typeName) {
122     entryPointTypeNames.add(typeName);
123   }
124
125   public void addGwtXmlFile(File JavaDoc xmlFile) {
126     gwtXmlFiles.add(xmlFile);
127   }
128
129   public synchronized void addPublicPackage(String JavaDoc publicPackage,
130       String JavaDoc[] includeList, String JavaDoc[] excludeList, boolean defaultExcludes,
131       boolean caseSensitive) {
132
133     if (lazyPublicOracle != null) {
134       throw new IllegalStateException JavaDoc("Already normalized");
135     }
136
137     /*
138      * Hijack Ant's ZipScanner to handle inclusions/exclusions exactly as Ant
139      * does. We're only using its pattern-matching capabilities; the code path
140      * I'm using never tries to hit the filesystem in Ant 1.6.5.
141      */

142     final ZipScanner scanner = new ZipScanner();
143     if (includeList.length > 0) {
144       scanner.setIncludes(includeList);
145     }
146     if (excludeList.length > 0) {
147       scanner.setExcludes(excludeList);
148     }
149     if (defaultExcludes) {
150       scanner.addDefaultExcludes();
151     }
152     scanner.setCaseSensitive(caseSensitive);
153     scanner.init();
154
155     // index from this package down
156
publicPathEntries.addRootPackage(publicPackage, new FileFilter() {
157       public boolean accept(String JavaDoc name) {
158         return scanner.match(name);
159       }
160     });
161   }
162
163   public synchronized void addSourcePackage(String JavaDoc sourcePackage) {
164     if (lazySourceOracle != null) {
165       throw new IllegalStateException JavaDoc("Already normalized");
166     }
167
168     // index from from the base package
169
sourcePathEntries.addPackage(sourcePackage, JAVA_ACCEPTOR);
170   }
171
172   public synchronized void addSuperSourcePackage(String JavaDoc superSourcePackage) {
173     if (lazySourceOracle != null) {
174       throw new IllegalStateException JavaDoc("Already normalized");
175     }
176
177     // index from this package down
178
sourcePathEntries.addRootPackage(superSourcePackage, JAVA_ACCEPTOR);
179   }
180
181   public void clearEntryPoints() {
182     entryPointTypeNames.clear();
183   }
184
185   public synchronized URL JavaDoc findPublicFile(String JavaDoc partialPath) {
186     return lazyPublicOracle.find(partialPath);
187   }
188
189   public synchronized String JavaDoc findServletForPath(String JavaDoc actual) {
190     // Walk in backwards sorted order to find the longest path match first.
191
//
192
Set JavaDoc entrySet = servletClassNamesByPath.entrySet();
193     Map.Entry JavaDoc[] entries = (Entry[]) Util.toArray(Map.Entry JavaDoc.class, entrySet);
194     Arrays.sort(entries, REV_NAME_CMP);
195     for (int i = 0, n = entries.length; i < n; ++i) {
196       String JavaDoc mapping = (String JavaDoc) entries[i].getKey();
197       /*
198        * Ensure that URLs that match the servlet mapping, including those that
199        * have additional path_info, get routed to the correct servlet.
200        *
201        * See "Inside Servlets", Second Edition, pg. 208
202        */

203       if (actual.equals(mapping) || actual.startsWith(mapping + "/")) {
204         return (String JavaDoc) entries[i].getValue();
205       }
206     }
207     return null;
208   }
209
210   public String JavaDoc[] getAllPublicFiles() {
211     return lazyPublicOracle.getAllFiles();
212   }
213
214   public CacheManager getCacheManager() {
215     return cacheManager;
216   }
217
218   public synchronized CompilationUnitProvider[] getCompilationUnits() {
219     return cups;
220   }
221
222   public synchronized String JavaDoc[] getEntryPointTypeNames() {
223     final int n = entryPointTypeNames.size();
224     return (String JavaDoc[]) entryPointTypeNames.toArray(new String JavaDoc[n]);
225   }
226
227   public synchronized String JavaDoc getFunctionName() {
228     return name.replace('.', '_');
229   }
230
231   public synchronized String JavaDoc getName() {
232     return name;
233   }
234
235   /**
236    * The properties that have been defined.
237    */

238   public synchronized Properties getProperties() {
239     return properties;
240   }
241
242   /**
243    * Gets a reference to the internal rules for this module def.
244    */

245   public synchronized Rules getRules() {
246     return rules;
247   }
248
249   /**
250    * Gets a reference to the internal scripts list for this module def.
251    */

252   public Scripts getScripts() {
253     return scripts;
254   }
255
256   public synchronized String JavaDoc[] getServletPaths() {
257     return (String JavaDoc[]) servletClassNamesByPath.keySet().toArray(Empty.STRINGS);
258   }
259
260   /**
261    * Gets a reference to the internal styles list for this module def.
262    */

263   public Styles getStyles() {
264     return styles;
265   }
266
267   public synchronized TypeOracle getTypeOracle(TreeLogger logger)
268       throws UnableToCompleteException {
269     if (lazyTypeOracle == null) {
270
271       // Refresh the type oracle.
272
//
273
try {
274         String JavaDoc msg = "Analyzing source in module '" + name + "'";
275         TreeLogger branch = logger.branch(TreeLogger.TRACE, msg, null);
276         long before = System.currentTimeMillis();
277         TypeOracleBuilder builder = new TypeOracleBuilder(getCacheManager());
278         CompilationUnitProvider[] currentCups = getCompilationUnits();
279         Arrays.sort(currentCups, CompilationUnitProvider.LOCATION_COMPARATOR);
280
281         TreeLogger subBranch = null;
282         if (branch.isLoggable(TreeLogger.DEBUG)) {
283           subBranch = branch.branch(TreeLogger.DEBUG,
284               "Adding compilation units...", null);
285         }
286
287         for (int i = 0; i < currentCups.length; i++) {
288           CompilationUnitProvider cup = currentCups[i];
289           if (subBranch != null) {
290             subBranch.log(TreeLogger.DEBUG, cup.getLocation(), null);
291           }
292           builder.addCompilationUnit(currentCups[i]);
293         }
294         lazyTypeOracle = builder.build(branch);
295         long after = System.currentTimeMillis();
296         branch.log(TreeLogger.TRACE, "Finished in " + (after - before) + " ms",
297             null);
298       } catch (UnableToCompleteException e) {
299         logger.log(TreeLogger.ERROR, "Failed to complete analysis", null);
300         throw new UnableToCompleteException();
301       }
302
303       // Sanity check the seed types and don't even start it they're missing.
304
//
305
boolean seedTypesMissing = false;
306       if (lazyTypeOracle.findType("java.lang.Object") == null) {
307         Util.logMissingTypeErrorWithHints(logger, "java.lang.Object");
308         seedTypesMissing = true;
309       } else {
310         TreeLogger branch = logger.branch(TreeLogger.TRACE,
311             "Finding entry point classes", null);
312         String JavaDoc[] typeNames = getEntryPointTypeNames();
313         for (int i = 0; i < typeNames.length; i++) {
314           String JavaDoc typeName = typeNames[i];
315           if (lazyTypeOracle.findType(typeName) == null) {
316             Util.logMissingTypeErrorWithHints(branch, typeName);
317             seedTypesMissing = true;
318           }
319         }
320       }
321
322       if (seedTypesMissing) {
323         throw new UnableToCompleteException();
324       }
325     }
326
327     return lazyTypeOracle;
328   }
329
330   public boolean isGwtXmlFileStale() {
331     for (Iterator JavaDoc iter = gwtXmlFiles.iterator(); iter.hasNext();) {
332       File JavaDoc xmlFile = (File JavaDoc) iter.next();
333       if ((!xmlFile.exists())
334           || (xmlFile.lastModified() > moduleDefCreationTime)) {
335         return true;
336       }
337     }
338     return false;
339   }
340
341   /**
342    * For convenience in hosted mode, servlets can be automatically loaded and
343    * delegated to via {@link com.google.gwt.dev.shell.GWTShellServlet}. If a
344    * servlet is already mapped to the specified path, it is replaced.
345    *
346    * @param path the url path at which the servlet resides
347    * @param servletClassName the name of the servlet to publish
348    */

349   public synchronized void mapServlet(String JavaDoc path, String JavaDoc servletClassName) {
350     servletClassNamesByPath.put(path, servletClassName);
351   }
352
353   public synchronized void refresh(TreeLogger logger)
354       throws UnableToCompleteException {
355
356     cacheManager.invalidateVolatileFiles();
357     lazyTypeOracle = null;
358     normalize(logger);
359     getTypeOracle(logger);
360     Util.invokeInaccessableMethod(TypeOracle.class, "incrementReloadCount",
361         new Class JavaDoc[] {}, lazyTypeOracle, new Object JavaDoc[] {});
362   }
363
364   /**
365    * The final method to call when everything is setup. Before calling this
366    * method, several of the getter methods may not be called. After calling this
367    * method, the add methods may not be called.
368    *
369    * @param logger Logs the activity.
370    */

371   synchronized void normalize(TreeLogger logger) {
372     // Normalize property providers.
373
//
374
for (Iterator JavaDoc iter = getProperties().iterator(); iter.hasNext();) {
375       Property prop = (Property) iter.next();
376       if (prop.getActiveValue() == null) {
377         // If there are more than one possible values, then create a provider.
378
// Otherwise, pretend the one value is an active value.
379
//
380
String JavaDoc[] knownValues = prop.getKnownValues();
381         assert (knownValues.length > 0);
382         if (knownValues.length > 1) {
383           if (prop.getProvider() == null) {
384             // Create a default provider.
385
//
386
prop.setProvider(new DefaultPropertyProvider(this, prop));
387           }
388         } else {
389           prop.setActiveValue(knownValues[0]);
390         }
391       }
392     }
393
394     // Create the source path.
395
//
396
TreeLogger branch = Messages.SOURCE_PATH_LOCATIONS.branch(logger, null);
397     lazySourceOracle = sourcePathEntries.create(branch);
398
399     if (lazySourceOracle.isEmpty()) {
400       branch.log(TreeLogger.WARN,
401           "No source path entries; expect subsequent failures", null);
402     } else {
403       // Create the CUPs
404
String JavaDoc[] allFiles = lazySourceOracle.getAllFiles();
405       Set JavaDoc files = new HashSet JavaDoc();
406       files.addAll(Arrays.asList(allFiles));
407       files.removeAll(alreadySeenFiles);
408       for (Iterator JavaDoc iter = files.iterator(); iter.hasNext();) {
409         String JavaDoc fileName = (String JavaDoc) iter.next();
410         int pos = fileName.lastIndexOf('/');
411         String JavaDoc packageName;
412         if (pos >= 0) {
413           packageName = fileName.substring(0, pos);
414           packageName = packageName.replace('/', '.');
415         } else {
416           packageName = "";
417         }
418         URL JavaDoc url = lazySourceOracle.find(fileName);
419         allCups.add(new URLCompilationUnitProvider(url, packageName));
420       }
421       alreadySeenFiles.addAll(files);
422       this.cups = (CompilationUnitProvider[]) allCups.toArray(this.cups);
423     }
424
425     // Create the public path.
426
//
427
branch = Messages.PUBLIC_PATH_LOCATIONS.branch(logger, null);
428     lazyPublicOracle = publicPathEntries.create(branch);
429   }
430
431 }
432
Popular Tags