Source Code Cross Referenced for GWTCompiler.java in  » Ajax » GWT » com » google » gwt » dev » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Ajax » GWT » com.google.gwt.dev 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * Copyright 2007 Google Inc.
0003:         * 
0004:         * Licensed under the Apache License, Version 2.0 (the "License"); you may not
0005:         * use this file except in compliance with the License. You may obtain a copy of
0006:         * the License at
0007:         * 
0008:         * http://www.apache.org/licenses/LICENSE-2.0
0009:         * 
0010:         * Unless required by applicable law or agreed to in writing, software
0011:         * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
0012:         * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
0013:         * License for the specific language governing permissions and limitations under
0014:         * the License.
0015:         */
0016:        package com.google.gwt.dev;
0017:
0018:        import com.google.gwt.core.ext.TreeLogger;
0019:        import com.google.gwt.core.ext.UnableToCompleteException;
0020:        import com.google.gwt.core.ext.TreeLogger.Type;
0021:        import com.google.gwt.core.ext.typeinfo.CompilationUnitProvider;
0022:        import com.google.gwt.core.ext.typeinfo.JClassType;
0023:        import com.google.gwt.core.ext.typeinfo.TypeOracle;
0024:        import com.google.gwt.dev.cfg.Compilation;
0025:        import com.google.gwt.dev.cfg.CompilationSchema;
0026:        import com.google.gwt.dev.cfg.Compilations;
0027:        import com.google.gwt.dev.cfg.ModuleDef;
0028:        import com.google.gwt.dev.cfg.ModuleDefLoader;
0029:        import com.google.gwt.dev.cfg.Properties;
0030:        import com.google.gwt.dev.cfg.Property;
0031:        import com.google.gwt.dev.cfg.PropertyPermutations;
0032:        import com.google.gwt.dev.cfg.Rules;
0033:        import com.google.gwt.dev.cfg.StaticPropertyOracle;
0034:        import com.google.gwt.dev.jdt.CacheManager;
0035:        import com.google.gwt.dev.jdt.RebindPermutationOracle;
0036:        import com.google.gwt.dev.jdt.StandardSourceOracle;
0037:        import com.google.gwt.dev.jdt.WebModeCompilerFrontEnd;
0038:        import com.google.gwt.dev.jjs.JJSOptions;
0039:        import com.google.gwt.dev.jjs.JsOutputOption;
0040:        import com.google.gwt.dev.jjs.JavaToJavaScriptCompiler;
0041:        import com.google.gwt.dev.shell.StandardRebindOracle;
0042:        import com.google.gwt.dev.util.DefaultTextOutput;
0043:        import com.google.gwt.dev.util.SelectionScriptGenerator;
0044:        import com.google.gwt.dev.util.Util;
0045:        import com.google.gwt.dev.util.arg.ArgHandlerGenDir;
0046:        import com.google.gwt.dev.util.arg.ArgHandlerLogLevel;
0047:        import com.google.gwt.dev.util.arg.ArgHandlerScriptStyle;
0048:        import com.google.gwt.dev.util.arg.ArgHandlerTreeLoggerFlag;
0049:        import com.google.gwt.dev.util.log.AbstractTreeLogger;
0050:        import com.google.gwt.dev.util.log.DetachedTreeLoggerWindow;
0051:        import com.google.gwt.dev.util.log.PrintWriterTreeLogger;
0052:        import com.google.gwt.dev.util.xml.ReflectiveParser;
0053:        import com.google.gwt.util.tools.ArgHandlerDisableAggressiveOptimization;
0054:        import com.google.gwt.util.tools.ArgHandlerExtra;
0055:        import com.google.gwt.util.tools.ArgHandlerFlag;
0056:        import com.google.gwt.util.tools.ArgHandlerOutDir;
0057:        import com.google.gwt.util.tools.ToolBase;
0058:        import com.google.gwt.util.tools.Utility;
0059:
0060:        import org.w3c.dom.Document;
0061:        import org.w3c.dom.Element;
0062:
0063:        import java.io.File;
0064:        import java.io.FileNotFoundException;
0065:        import java.io.FileReader;
0066:        import java.io.FilenameFilter;
0067:        import java.io.UnsupportedEncodingException;
0068:        import java.net.URL;
0069:        import java.util.ArrayList;
0070:        import java.util.HashMap;
0071:        import java.util.HashSet;
0072:        import java.util.Iterator;
0073:        import java.util.List;
0074:        import java.util.Map;
0075:        import java.util.Set;
0076:
0077:        import javax.xml.parsers.DocumentBuilder;
0078:        import javax.xml.parsers.DocumentBuilderFactory;
0079:        import javax.xml.parsers.ParserConfigurationException;
0080:
0081:        /**
0082:         * The main executable entry point for the GWT Java to JavaScript compiler.
0083:         */
0084:        public class GWTCompiler extends ToolBase {
0085:
0086:            private class ArgHandlerModuleName extends ArgHandlerExtra {
0087:
0088:                @Override
0089:                public boolean addExtraArg(String arg) {
0090:                    setModuleName(arg);
0091:                    return true;
0092:                }
0093:
0094:                @Override
0095:                public String getPurpose() {
0096:                    return "Specifies the name of the module to compile";
0097:                }
0098:
0099:                @Override
0100:                public String[] getTagArgs() {
0101:                    return new String[] { "module" };
0102:                }
0103:
0104:                @Override
0105:                public boolean isRequired() {
0106:                    return true;
0107:                }
0108:            }
0109:
0110:            /**
0111:             * Argument handler for making the compiler run in "validation" mode.
0112:             */
0113:            private class ArgHandlerValidateOnlyFlag extends ArgHandlerFlag {
0114:
0115:                public String getPurpose() {
0116:                    return "Validate all source code, but do not compile";
0117:                }
0118:
0119:                public String getTag() {
0120:                    return "-validateOnly";
0121:                }
0122:
0123:                public boolean setFlag() {
0124:                    jjsOptions.setValidateOnly(true);
0125:                    return true;
0126:                }
0127:            }
0128:
0129:            /**
0130:             * Used to smartly deal with rebind across the production of an entire
0131:             * permutation, including cache checking and recording the inputs and outputs
0132:             * into a {@link Compilation}.
0133:             */
0134:            private class CompilationRebindOracle extends StandardRebindOracle {
0135:
0136:                private final Map<String, String> cache = new HashMap<String, String>();
0137:
0138:                private Compilation compilation;
0139:
0140:                public CompilationRebindOracle() {
0141:                    super (typeOracle, propOracle, module, rules, genDir,
0142:                            outDir, cacheManager);
0143:                }
0144:
0145:                /**
0146:                 * Overridden so that we can selectively record inputs and outputs to derive
0147:                 * the cache key for a compilation. Note that the cache gets invalidated if
0148:                 * the propOracle changes state.
0149:                 */
0150:                @Override
0151:                public String rebind(TreeLogger logger, String in)
0152:                        throws UnableToCompleteException {
0153:                    String out = cache.get(in);
0154:                    if (out == null) {
0155:                        // Actually do the work, then cache it.
0156:                        //
0157:                        out = super .rebind(logger, in);
0158:                        cache.put(in, out);
0159:                    } else {
0160:                        // Was cached.
0161:                        //
0162:                        String msg = "Rebind answer for '" + in
0163:                                + "' found in cache " + out;
0164:                        logger.log(TreeLogger.DEBUG, msg, null);
0165:                    }
0166:
0167:                    if (compilation != null
0168:                            && compilation.recordDecision(in, out)) {
0169:                        List<JClassType> genTypes = generatedTypesByResultTypeName
0170:                                .get(out);
0171:                        if (genTypes != null) {
0172:                            for (JClassType genType : genTypes) {
0173:                                String sourceHash = genType.getTypeHash();
0174:                                String genTypeName = genType
0175:                                        .getQualifiedSourceName();
0176:                                compilation.recordGeneratedTypeHash(
0177:                                        genTypeName, sourceHash);
0178:                            }
0179:                        }
0180:                    }
0181:
0182:                    return out;
0183:                }
0184:
0185:                public void recordInto(Compilation compilation) {
0186:                    this .compilation = compilation;
0187:                }
0188:            }
0189:
0190:            private class DistillerRebindPermutationOracle implements 
0191:                    RebindPermutationOracle {
0192:
0193:                private final StandardRebindOracle rebindOracle = new StandardRebindOracle(
0194:                        typeOracle, propOracle, module, rules, genDir, outDir,
0195:                        cacheManager) {
0196:
0197:                    /**
0198:                     * Record generated types.
0199:                     */
0200:                    @Override
0201:                    protected void onGeneratedTypes(String result,
0202:                            JClassType[] genTypes) {
0203:                        List<JClassType> list = new ArrayList<JClassType>();
0204:                        Util.addAll(list, genTypes);
0205:                        Object existing = generatedTypesByResultTypeName.put(
0206:                                result, list);
0207:                        assert (existing == null) : "Internal error: redundant notification of generated types";
0208:                    }
0209:                };
0210:
0211:                public String[] getAllPossibleRebindAnswers(TreeLogger logger,
0212:                        String requestTypeName)
0213:                        throws UnableToCompleteException {
0214:
0215:                    String msg = "Computing all possible rebind results for '"
0216:                            + requestTypeName + "'";
0217:                    logger = logger.branch(TreeLogger.DEBUG, msg, null);
0218:
0219:                    Set<String> answers = new HashSet<String>();
0220:
0221:                    Property[] orderedProps = perms.getOrderedProperties();
0222:                    for (Iterator<String[]> iter = perms.iterator(); iter
0223:                            .hasNext();) {
0224:                        String[] orderedPropValues = iter.next();
0225:
0226:                        // Create a snapshot of the property values by setting their values
0227:                        // in the property oracle. Because my rebindOracle uses the shared
0228:                        // generator context (which in turns uses the propOracle), this
0229:                        // has the effect we're after. It isn't reentrant, though, so don't
0230:                        // expect to call this recursively.
0231:                        propOracle.setPropertyValues(orderedProps,
0232:                                orderedPropValues);
0233:
0234:                        // Ask the rebind oracle.
0235:                        logProperties(logger, orderedProps, orderedPropValues);
0236:                        String resultTypeName = rebindOracle.rebind(logger,
0237:                                requestTypeName);
0238:                        answers.add(resultTypeName);
0239:                    }
0240:                    return Util.toArray(String.class, answers);
0241:                }
0242:            }
0243:
0244:            private static final String EXT_CACHE_XML = ".cache.xml";
0245:
0246:            public static void main(String[] args) {
0247:                /*
0248:                 * NOTE: main always exits with a call to System.exit to terminate any
0249:                 * non-daemon threads that were started in Generators. Typically, this is to
0250:                 * shutdown AWT related threads, since the contract for their termination is
0251:                 * still implementation-dependent.
0252:                 */
0253:                GWTCompiler compiler = new GWTCompiler();
0254:                if (compiler.processArgs(args)) {
0255:                    if (compiler.run()) {
0256:                        // Exit w/ success code.
0257:                        System.exit(0);
0258:                    }
0259:                }
0260:                // Exit w/ non-success code.
0261:                System.exit(1);
0262:            }
0263:
0264:            /**
0265:             * Returns the fully-qualified main type name of a compilation unit.
0266:             */
0267:            private static String makeTypeName(CompilationUnitProvider cup) {
0268:                if (cup.getPackageName().length() > 0) {
0269:                    return cup.getPackageName() + "." + cup.getMainTypeName();
0270:                } else {
0271:                    return cup.getMainTypeName();
0272:                }
0273:            }
0274:
0275:            private final CacheManager cacheManager;
0276:
0277:            private Compilations compilations = new Compilations();
0278:
0279:            private String[] declEntryPts;
0280:
0281:            private File genDir;
0282:
0283:            private Map<String, List<JClassType>> generatedTypesByResultTypeName = new HashMap<String, List<JClassType>>();
0284:
0285:            private JavaToJavaScriptCompiler jjs;
0286:
0287:            private JJSOptions jjsOptions = new JJSOptions();
0288:
0289:            private Type logLevel;
0290:
0291:            private ModuleDef module;
0292:
0293:            private String moduleName;
0294:
0295:            private File outDir;
0296:
0297:            private PropertyPermutations perms;
0298:
0299:            private Properties properties;
0300:
0301:            private StaticPropertyOracle propOracle = new StaticPropertyOracle();
0302:
0303:            private RebindPermutationOracle rebindPermOracle;
0304:
0305:            private Rules rules;
0306:
0307:            private StandardSourceOracle sourceOracle;
0308:
0309:            private TypeOracle typeOracle;
0310:
0311:            private boolean useGuiLogger;
0312:
0313:            public GWTCompiler() {
0314:                this (null);
0315:            }
0316:
0317:            public GWTCompiler(CacheManager cacheManager) {
0318:                registerHandler(new ArgHandlerLogLevel() {
0319:                    @Override
0320:                    public void setLogLevel(Type level) {
0321:                        logLevel = level;
0322:                    }
0323:                });
0324:
0325:                registerHandler(new ArgHandlerGenDir() {
0326:                    @Override
0327:                    public void setDir(File dir) {
0328:                        genDir = dir;
0329:                    }
0330:                });
0331:
0332:                registerHandler(new ArgHandlerOutDir() {
0333:                    @Override
0334:                    public void setDir(File dir) {
0335:                        outDir = dir;
0336:                    }
0337:                });
0338:
0339:                registerHandler(new ArgHandlerTreeLoggerFlag() {
0340:                    @Override
0341:                    public boolean setFlag() {
0342:                        useGuiLogger = true;
0343:                        return true;
0344:                    }
0345:                });
0346:
0347:                registerHandler(new ArgHandlerModuleName());
0348:
0349:                registerHandler(new ArgHandlerScriptStyle(jjsOptions));
0350:
0351:                registerHandler(new ArgHandlerDisableAggressiveOptimization() {
0352:                    @Override
0353:                    public boolean setFlag() {
0354:                        GWTCompiler.this .setAggressivelyOptimize(false);
0355:                        return true;
0356:                    }
0357:                });
0358:
0359:                registerHandler(new ArgHandlerValidateOnlyFlag());
0360:
0361:                this .cacheManager = cacheManager;
0362:            }
0363:
0364:            public void distill(TreeLogger logger, ModuleDef moduleDef)
0365:                    throws UnableToCompleteException {
0366:                this .module = moduleDef;
0367:
0368:                // Set up all the initial state.
0369:                checkModule(logger);
0370:
0371:                // Tweak the output directory so that output lives under the module name.
0372:                outDir = new File(outDir, module.getName());
0373:
0374:                rules = module.getRules();
0375:                typeOracle = module.getTypeOracle(logger);
0376:                sourceOracle = new StandardSourceOracle(typeOracle);
0377:                if (jjsOptions.isValidateOnly()) {
0378:                    // Pretend that every single compilation unit is an entry point.
0379:                    CompilationUnitProvider[] compilationUnits = module
0380:                            .getCompilationUnits();
0381:                    declEntryPts = new String[compilationUnits.length];
0382:                    for (int i = 0; i < compilationUnits.length; ++i) {
0383:                        CompilationUnitProvider cup = compilationUnits[i];
0384:                        declEntryPts[i] = makeTypeName(cup);
0385:                    }
0386:                } else {
0387:                    // Use the real entry points.
0388:                    declEntryPts = module.getEntryPointTypeNames();
0389:                }
0390:                rebindPermOracle = new DistillerRebindPermutationOracle();
0391:                properties = module.getProperties();
0392:                perms = new PropertyPermutations(properties);
0393:                WebModeCompilerFrontEnd frontEnd = new WebModeCompilerFrontEnd(
0394:                        sourceOracle, rebindPermOracle);
0395:                jjs = new JavaToJavaScriptCompiler(logger, frontEnd,
0396:                        declEntryPts, jjsOptions);
0397:
0398:                if (!jjsOptions.isValidateOnly()) {
0399:                    /*
0400:                     * See what permutations already exist on disk and are up to date. Skip
0401:                     * this for validation mode since we want to recompile everything.
0402:                     */
0403:                    initCompilations(logger);
0404:                }
0405:
0406:                // Compile for every permutation of properties.
0407:                //
0408:                SelectionScriptGenerator selGen = compilePermutations(logger);
0409:
0410:                if (jjsOptions.isValidateOnly()) {
0411:                    logger.log(TreeLogger.INFO, "Validation succeeded", null);
0412:                    return;
0413:                }
0414:
0415:                // Generate a selection script to pick the right permutation.
0416:                //
0417:                writeSelectionScripts(logger, selGen);
0418:
0419:                // Copy all public files into the output directory.
0420:                //
0421:                copyPublicFiles(logger);
0422:
0423:                logger.log(TreeLogger.INFO, "Compilation succeeded", null);
0424:            }
0425:
0426:            public File getGenDir() {
0427:                return genDir;
0428:            }
0429:
0430:            public Type getLogLevel() {
0431:                return logLevel;
0432:            }
0433:
0434:            public String getModuleName() {
0435:                return moduleName;
0436:            }
0437:
0438:            public boolean getUseGuiLogger() {
0439:                return useGuiLogger;
0440:            }
0441:
0442:            public void setAggressivelyOptimize(boolean aggressive) {
0443:                jjsOptions.setAggressivelyOptimize(aggressive);
0444:            }
0445:
0446:            public void setCompilerOptions(JJSOptions options) {
0447:                jjsOptions.copyFrom(options);
0448:            }
0449:
0450:            public void setGenDir(File dir) {
0451:                genDir = dir;
0452:            }
0453:
0454:            public void setLogLevel(Type level) {
0455:                this .logLevel = level;
0456:            }
0457:
0458:            public void setModuleName(String name) {
0459:                moduleName = name;
0460:            }
0461:
0462:            public void setOutDir(File outDir) {
0463:                this .outDir = outDir;
0464:            }
0465:
0466:            public void setStyleDetailed() {
0467:                jjsOptions.setOutput(JsOutputOption.DETAILED);
0468:            }
0469:
0470:            public void setStyleObfuscated() {
0471:                jjsOptions.setOutput(JsOutputOption.OBFUSCATED);
0472:            }
0473:
0474:            public void setStylePretty() {
0475:                jjsOptions.setOutput(JsOutputOption.PRETTY);
0476:            }
0477:
0478:            /**
0479:             * Ensure the module has at least one entry point (except in validation mode).
0480:             */
0481:            private void checkModule(TreeLogger logger)
0482:                    throws UnableToCompleteException {
0483:                if (!jjsOptions.isValidateOnly()
0484:                        && module.getEntryPointTypeNames().length == 0) {
0485:                    logger.log(TreeLogger.ERROR,
0486:                            "Module has no entry points defined", null);
0487:                    throw new UnableToCompleteException();
0488:                }
0489:            }
0490:
0491:            private SelectionScriptGenerator compilePermutations(
0492:                    TreeLogger logger) throws UnableToCompleteException {
0493:                if (jjsOptions.isValidateOnly()) {
0494:                    logger = logger.branch(TreeLogger.INFO,
0495:                            "Validating compilation", null);
0496:                } else {
0497:                    logger = logger.branch(TreeLogger.INFO, "Compiling into "
0498:                            + outDir, null);
0499:                }
0500:                Property[] orderedProps = perms.getOrderedProperties();
0501:                SelectionScriptGenerator selGen = new SelectionScriptGenerator(
0502:                        module, orderedProps);
0503:                int permNumber = 1;
0504:                for (Iterator<String[]> iter = perms.iterator(); iter.hasNext(); ++permNumber) {
0505:
0506:                    String[] orderedPropValues = iter.next();
0507:                    String strongName = realizePermutation(logger,
0508:                            orderedProps, orderedPropValues, permNumber);
0509:                    if (!jjsOptions.isValidateOnly()) {
0510:                        selGen.recordSelection(orderedPropValues, strongName);
0511:                    }
0512:                }
0513:                return selGen;
0514:            }
0515:
0516:            private void copyPublicFiles(TreeLogger logger)
0517:                    throws UnableToCompleteException {
0518:                TreeLogger branch = null;
0519:                boolean anyCopied = false;
0520:                String[] files = module.getAllPublicFiles();
0521:                for (int i = 0; i < files.length; ++i) {
0522:                    URL from = module.findPublicFile(files[i]);
0523:                    File to = new File(outDir, files[i]);
0524:                    boolean copied = Util.copy(logger, from, to);
0525:                    if (copied) {
0526:                        if (!anyCopied) {
0527:                            branch = logger.branch(TreeLogger.INFO,
0528:                                    "Copying all files found on public path",
0529:                                    null);
0530:                            if (!logger.isLoggable(TreeLogger.TRACE)) {
0531:                                branch = null;
0532:                            }
0533:                            anyCopied = true;
0534:                        }
0535:
0536:                        if (branch != null) {
0537:                            branch.log(TreeLogger.TRACE, to.getAbsolutePath(),
0538:                                    null);
0539:                        }
0540:                    }
0541:                }
0542:            }
0543:
0544:            private String getHtmlPrefix() {
0545:                DefaultTextOutput out = new DefaultTextOutput(jjsOptions
0546:                        .getOutput().shouldMinimize());
0547:                out.print("<html>");
0548:                out.newlineOpt();
0549:
0550:                // Setup the well-known variables.
0551:                //
0552:                out.print("<head><script>");
0553:                out.newlineOpt();
0554:                out.print("var $gwt_version = \"" + About.GWT_VERSION_NUM
0555:                        + "\";");
0556:                out.newlineOpt();
0557:                out.print("var $wnd = parent;");
0558:                out.newlineOpt();
0559:                out.print("var $doc = $wnd.document;");
0560:                out.newlineOpt();
0561:                out.print("var $moduleName, $moduleBase;");
0562:                out.newlineOpt();
0563:                out.print("</script></head>");
0564:                out.newlineOpt();
0565:                out.print("<body>");
0566:                out.newlineOpt();
0567:
0568:                // Begin a script block inside the body. It's commented out so that the
0569:                // browser won't mistake strings containing "<script>" for actual script.
0570:                out.print("<script><!--");
0571:                out.newline();
0572:                return out.toString();
0573:            }
0574:
0575:            private String getHtmlSuffix() {
0576:                DefaultTextOutput out = new DefaultTextOutput(jjsOptions
0577:                        .getOutput().shouldMinimize());
0578:                String moduleFunction = module.getName().replace('.', '_');
0579:
0580:                // Generate the call to tell the bootstrap code that we're ready to go.
0581:                out.newlineOpt();
0582:                out.print("if ($wnd." + moduleFunction + ") $wnd."
0583:                        + moduleFunction + ".onScriptLoad();");
0584:                out.newline();
0585:                out.print("--></script></body></html>");
0586:                out.newlineOpt();
0587:
0588:                return out.toString();
0589:            }
0590:
0591:            private String getJsPrefix() {
0592:                DefaultTextOutput out = new DefaultTextOutput(jjsOptions
0593:                        .getOutput().shouldMinimize());
0594:
0595:                out.print("(function(){");
0596:                out.newlineOpt();
0597:
0598:                // Setup the well-known variables.
0599:                //
0600:                out.print("var $gwt_version = \"" + About.GWT_VERSION_NUM
0601:                        + "\";");
0602:                out.newlineOpt();
0603:                out.print("var $wnd = window;");
0604:                out.newlineOpt();
0605:                out.print("var $doc = $wnd.document;");
0606:                out.newlineOpt();
0607:                out.print("var $moduleName, $moduleBase;");
0608:                out.newlineOpt();
0609:
0610:                return out.toString();
0611:            }
0612:
0613:            private String getJsSuffix() {
0614:                DefaultTextOutput out = new DefaultTextOutput(jjsOptions
0615:                        .getOutput().shouldMinimize());
0616:                String moduleFunction = module.getName().replace('.', '_');
0617:
0618:                // Generate the call to tell the bootstrap code that we're ready to go.
0619:                out.newlineOpt();
0620:                out.print("if (" + moduleFunction + ") {");
0621:                out.newlineOpt();
0622:                out.print("  var __gwt_initHandlers = " + moduleFunction
0623:                        + ".__gwt_initHandlers;");
0624:                out.print("  " + moduleFunction + ".onScriptLoad(gwtOnLoad);");
0625:                out.newlineOpt();
0626:                out.print("}");
0627:                out.newlineOpt();
0628:                out.print("})();");
0629:                out.newlineOpt();
0630:
0631:                return out.toString();
0632:            }
0633:
0634:            /**
0635:             * This has to run after JJS exists which means that all rebind perms have
0636:             * happened and thus the type oracle knows about everything.
0637:             */
0638:            private void initCompilations(TreeLogger logger)
0639:                    throws UnableToCompleteException {
0640:                File[] cacheXmls = outDir.listFiles(new FilenameFilter() {
0641:                    public boolean accept(File dir, String name) {
0642:                        return name.endsWith(EXT_CACHE_XML);
0643:                    }
0644:                });
0645:
0646:                if (cacheXmls == null) {
0647:                    return;
0648:                }
0649:
0650:                long newestCup = jjs
0651:                        .getLastModifiedTimeOfNewestCompilationUnit();
0652:                for (int i = 0; i < cacheXmls.length; i++) {
0653:                    File cacheXml = cacheXmls[i];
0654:                    String fn = cacheXml.getName();
0655:                    String strongName = fn.substring(0, fn.length()
0656:                            - EXT_CACHE_XML.length());
0657:
0658:                    // Make sure the cached script is not out of date.
0659:                    //
0660:                    long cacheXmlLastMod = cacheXml.lastModified();
0661:                    if (cacheXmlLastMod < newestCup) {
0662:                        // It is out of date; no need to even parse the XML.
0663:                        //
0664:                        String msg = "Compilation '" + fn
0665:                                + "' is out of date and will be removed";
0666:                        logger.log(TreeLogger.TRACE, msg, null);
0667:                        Util.deleteFilesStartingWith(outDir, strongName);
0668:                        continue;
0669:                    }
0670:
0671:                    // It is up-to-date, so we at least can load it.
0672:                    // We still need to verify that the source for generated types hasn't
0673:                    // changed.
0674:                    //
0675:                    TreeLogger branch = logger.branch(TreeLogger.DEBUG,
0676:                            "Loading cached compilation: " + cacheXml, null);
0677:                    Compilation c = new Compilation();
0678:                    c.setStrongName(strongName);
0679:                    CompilationSchema schema = new CompilationSchema(c);
0680:                    FileReader r = null;
0681:                    Throwable caught = null;
0682:                    try {
0683:                        r = new FileReader(cacheXml);
0684:                        ReflectiveParser.parse(logger, schema, r);
0685:                    } catch (FileNotFoundException e) {
0686:                        caught = e;
0687:                    } catch (UnableToCompleteException e) {
0688:                        caught = e;
0689:                    } finally {
0690:                        Utility.close(r);
0691:                    }
0692:
0693:                    if (caught != null) {
0694:                        String msg = "Unable to load the cached file";
0695:                        branch.log(TreeLogger.WARN, msg, caught);
0696:                        continue;
0697:                    }
0698:
0699:                    // Check that the hash code of the generated sources for this compilation
0700:                    // matches the current generated source for the same type.
0701:                    //
0702:                    boolean isBadCompilation = false;
0703:                    String[] genTypes = c.getGeneratedTypeNames();
0704:                    for (int j = 0; j < genTypes.length; j++) {
0705:                        String genTypeName = genTypes[j];
0706:                        String cachedHash = c.getTypeHash(genTypeName);
0707:                        JClassType genType = typeOracle.findType(genTypeName);
0708:                        if (genType == null) {
0709:                            // This cache entry refers to a type that no longer seems to exist.
0710:                            // Remove it.
0711:                            //
0712:                            String msg = "Compilation '"
0713:                                    + fn
0714:                                    + "' refers to generated type '"
0715:                                    + genTypeName
0716:                                    + "' which no longer exists; cache entry will be removed";
0717:                            branch.log(TreeLogger.TRACE, msg, null);
0718:                            Util.deleteFilesStartingWith(outDir, strongName);
0719:                            isBadCompilation = true;
0720:                            break;
0721:                        }
0722:
0723:                        String currentHash = genType.getTypeHash();
0724:
0725:                        if (!cachedHash.equals(currentHash)) {
0726:                            String msg = "Compilation '"
0727:                                    + fn
0728:                                    + "' was compiled with a different version of generated source for '"
0729:                                    + genTypeName
0730:                                    + "'; cache entry will be removed";
0731:                            branch.log(TreeLogger.TRACE, msg, null);
0732:                            Util.deleteFilesStartingWith(outDir, strongName);
0733:                            isBadCompilation = true;
0734:                            break;
0735:                        }
0736:                    }
0737:
0738:                    if (!isBadCompilation) {
0739:                        // Okay -- this compilation should be a cache candidate.
0740:                        compilations.add(c);
0741:                    }
0742:                }
0743:            }
0744:
0745:            private void logProperties(TreeLogger logger, Property[] props,
0746:                    String[] values) {
0747:                if (logger.isLoggable(TreeLogger.DEBUG)) {
0748:                    logger = logger.branch(TreeLogger.DEBUG,
0749:                            "Setting properties", null);
0750:                    for (int i = 0; i < props.length; i++) {
0751:                        String name = props[i].getName();
0752:                        String value = values[i];
0753:                        logger
0754:                                .log(TreeLogger.TRACE, name + " = " + value,
0755:                                        null);
0756:                    }
0757:                }
0758:            }
0759:
0760:            /**
0761:             * Attempts to compile with a single permutation of properties. The result can
0762:             * be one of the following:
0763:             * <ul>
0764:             * <li>There is an existing compilation having the same deferred binding
0765:             * results (and thus would create identical output); compilation is skipped
0766:             * <li>No existing compilation unit matches, so the compilation proceeds
0767:             * </ul>
0768:             */
0769:            private String realizePermutation(TreeLogger logger,
0770:                    Property[] currentProps, String[] currentValues,
0771:                    int permNumber) throws UnableToCompleteException {
0772:                String msg = "Analyzing permutation #" + permNumber;
0773:                logger = logger.branch(TreeLogger.TRACE, msg, null);
0774:
0775:                logProperties(logger, currentProps, currentValues);
0776:
0777:                // Create a rebind oracle that will record decisions so that we can cache
0778:                // them and avoid future computations.
0779:                //
0780:                CompilationRebindOracle rebindOracle = new CompilationRebindOracle();
0781:
0782:                // Tell the property provider above about the current property values.
0783:                // Note that the rebindOracle is actually sensitive to these values because
0784:                // in its ctor is uses propOracle as its property oracle.
0785:                //
0786:                propOracle.setPropertyValues(currentProps, currentValues);
0787:
0788:                // Check to see if we already have this compilation.
0789:                // This will have the effect of filling the rebind oracle's cache.
0790:                //
0791:                String[] entryPts = module.getEntryPointTypeNames();
0792:                Compilation cached = compilations.find(logger, rebindOracle,
0793:                        entryPts);
0794:                if (cached != null) {
0795:                    msg = "Matches existing compilation "
0796:                            + cached.getStrongName();
0797:                    logger.log(TreeLogger.TRACE, msg, null);
0798:                    return cached.getStrongName();
0799:                }
0800:
0801:                // Now attach a compilation into which we can record the particular inputs
0802:                // and outputs used by this compile process.
0803:                //
0804:                Compilation compilation = new Compilation();
0805:                rebindOracle.recordInto(compilation);
0806:
0807:                // Create JavaScript.
0808:                //
0809:                String js = jjs.compile(logger, rebindOracle);
0810:                if (jjsOptions.isValidateOnly()) {
0811:                    // We're done, there's no actual script to write.
0812:                    assert (js == null);
0813:                    return null;
0814:                }
0815:
0816:                // Create a wrapper and an unambiguous name for the file.
0817:                //
0818:                String strongName = writeHtmlAndJsWithStrongName(logger, js);
0819:
0820:                // Write out a cache control file that correlates to this script.
0821:                //
0822:                compilation.setStrongName(strongName);
0823:                writeCacheFile(logger, compilation);
0824:
0825:                // Add this compilation to the list of known compilations.
0826:                //
0827:                compilations.add(compilation);
0828:                return compilation.getStrongName();
0829:            }
0830:
0831:            /**
0832:             * Runs the compiler. If a gui-based TreeLogger is used, this method will not
0833:             * return until its window is closed by the user.
0834:             * 
0835:             * @return success from the compiler, <code>true</code> if the compile
0836:             *         completed without errors, <code>false</code> otherwise.
0837:             */
0838:            private boolean run() {
0839:                // Set any platform specific system properties.
0840:                BootStrapPlatform.setSystemProperties();
0841:
0842:                if (useGuiLogger) {
0843:                    // Initialize a tree logger window.
0844:                    DetachedTreeLoggerWindow loggerWindow = DetachedTreeLoggerWindow
0845:                            .getInstance("Build Output for " + moduleName, 800,
0846:                                    600, true);
0847:
0848:                    // Eager AWT initialization for OS X to ensure safe coexistence with SWT.
0849:                    BootStrapPlatform.maybeInitializeAWT();
0850:
0851:                    final AbstractTreeLogger logger = loggerWindow.getLogger();
0852:                    final boolean[] success = new boolean[1];
0853:
0854:                    // Compiler will be spawned onto a second thread, UI thread for tree
0855:                    // logger will remain on the main.
0856:                    Thread compilerThread = new Thread(new Runnable() {
0857:                        public void run() {
0858:                            success[0] = GWTCompiler.this .run(logger);
0859:                        }
0860:                    });
0861:
0862:                    compilerThread.setName("GWTCompiler Thread");
0863:                    compilerThread.start();
0864:                    loggerWindow.run();
0865:
0866:                    // Even if the tree logger window is closed, we wait for the compiler
0867:                    // to finish.
0868:                    waitForThreadToTerminate(compilerThread);
0869:
0870:                    return success[0];
0871:                } else {
0872:                    return run(new PrintWriterTreeLogger());
0873:                }
0874:            }
0875:
0876:            private boolean run(AbstractTreeLogger logger) {
0877:                try {
0878:                    logger.setMaxDetail(logLevel);
0879:
0880:                    ModuleDef moduleDef = ModuleDefLoader.loadFromClassPath(
0881:                            logger, moduleName);
0882:                    distill(logger, moduleDef);
0883:                    return true;
0884:                } catch (UnableToCompleteException e) {
0885:                    // We intentionally don't pass in the exception here since the real
0886:                    // cause has been logged.
0887:                    logger.log(TreeLogger.ERROR, "Build failed", null);
0888:                    return false;
0889:                }
0890:            }
0891:
0892:            /**
0893:             * Waits for a thread to terminate before it returns. This method is a
0894:             * non-cancellable task, in that it will defer thread interruption until it is
0895:             * done.
0896:             * 
0897:             * @param godot the thread that is being waited on.
0898:             */
0899:            private void waitForThreadToTerminate(final Thread godot) {
0900:                // Goetz pattern for non-cancellable tasks.
0901:                // http://www-128.ibm.com/developerworks/java/library/j-jtp05236.html
0902:                boolean isInterrupted = false;
0903:                try {
0904:                    while (true) {
0905:                        try {
0906:                            godot.join();
0907:                            return;
0908:                        } catch (InterruptedException e) {
0909:                            isInterrupted = true;
0910:                        }
0911:                    }
0912:                } finally {
0913:                    if (isInterrupted) {
0914:                        Thread.currentThread().interrupt();
0915:                    }
0916:                }
0917:            }
0918:
0919:            private void writeCacheFile(TreeLogger logger,
0920:                    Compilation compilation) throws UnableToCompleteException {
0921:                // Create and write the cache file.
0922:                // The format matches the one read in consumeCacheEntry().
0923:                //
0924:                DocumentBuilderFactory dbf = DocumentBuilderFactory
0925:                        .newInstance();
0926:                DocumentBuilder db;
0927:                try {
0928:                    db = dbf.newDocumentBuilder();
0929:                } catch (ParserConfigurationException e) {
0930:                    logger.log(TreeLogger.ERROR,
0931:                            "Unable to construct cache entry XML", e);
0932:                    throw new UnableToCompleteException();
0933:                }
0934:                Document doc = db.newDocument();
0935:
0936:                // <cache-entry ...>
0937:                Element docElem = doc.createElement("cache-entry");
0938:                doc.appendChild(docElem);
0939:
0940:                // <generated-type-hash ...>
0941:                String[] genTypeNames = compilation.getGeneratedTypeNames();
0942:                for (int i = 0; i < genTypeNames.length; i++) {
0943:                    String genTypeName = genTypeNames[i];
0944:                    String hash = compilation.getTypeHash(genTypeName);
0945:                    Element childElem = doc
0946:                            .createElement("generated-type-hash");
0947:                    docElem.appendChild(childElem);
0948:                    childElem.setAttribute("class", genTypeName);
0949:                    childElem.setAttribute("hash", hash);
0950:                }
0951:
0952:                // deferred binding decisions
0953:                String[] inputs = compilation.getRebindInputs();
0954:                for (int i = 0, n = inputs.length; i < n; ++i) {
0955:                    String in = inputs[i];
0956:                    String out = compilation.getRebindOutput(in);
0957:
0958:                    // <rebind-decision ...>
0959:                    Element childElem = doc.createElement("rebind-decision");
0960:                    docElem.appendChild(childElem);
0961:                    childElem.setAttribute("in", in);
0962:                    childElem.setAttribute("out", out);
0963:                }
0964:
0965:                // Persist it.
0966:                //
0967:                String strongName = compilation.getStrongName();
0968:                File cacheFile = new File(outDir, strongName + EXT_CACHE_XML);
0969:                byte[] bytes = Util.toXmlUtf8(doc);
0970:                Util.writeBytesToFile(logger, cacheFile, bytes);
0971:
0972:                String msg = "Compilation metadata written to "
0973:                        + cacheFile.getAbsolutePath();
0974:                logger.log(TreeLogger.TRACE, msg, null);
0975:            }
0976:
0977:            /**
0978:             * Writes the script to 1) an HTML file containing the script and 2) a
0979:             * JavaScript file containing the script. Contenst are encoded as UTF-8, and
0980:             * the filenames will be an MD5 hash of the script contents.
0981:             * 
0982:             * @return the base part of the strong name, which can be used to create other
0983:             *         files with different extensions
0984:             */
0985:            private String writeHtmlAndJsWithStrongName(TreeLogger logger,
0986:                    String js) throws UnableToCompleteException {
0987:                try {
0988:                    byte[] scriptBytes = js.getBytes("UTF-8");
0989:                    String strongName = Util.computeStrongName(scriptBytes);
0990:                    {
0991:                        byte[] prefix = getHtmlPrefix().getBytes("UTF-8");
0992:                        byte[] suffix = getHtmlSuffix().getBytes("UTF-8");
0993:                        File outFile = new File(outDir, strongName
0994:                                + ".cache.html");
0995:                        Util.writeBytesToFile(logger, outFile, new byte[][] {
0996:                                prefix, scriptBytes, suffix });
0997:                        String msg = "Compilation written to "
0998:                                + outFile.getAbsolutePath();
0999:                        logger.log(TreeLogger.TRACE, msg, null);
1000:                    }
1001:                    {
1002:                        byte[] prefix = getJsPrefix().getBytes("UTF-8");
1003:                        byte[] suffix = getJsSuffix().getBytes("UTF-8");
1004:                        File outFile = new File(outDir, strongName
1005:                                + ".cache.js");
1006:                        Util.writeBytesToFile(logger, outFile, new byte[][] {
1007:                                prefix, scriptBytes, suffix });
1008:                        String msg = "Compilation written to "
1009:                                + outFile.getAbsolutePath();
1010:                        logger.log(TreeLogger.TRACE, msg, null);
1011:                    }
1012:                    return strongName;
1013:                } catch (UnsupportedEncodingException e) {
1014:                    logger.log(TreeLogger.ERROR,
1015:                            "Unable to encode compiled script as UTF-8", e);
1016:                    throw new UnableToCompleteException();
1017:                }
1018:            }
1019:
1020:            private void writeSelectionScripts(TreeLogger logger,
1021:                    SelectionScriptGenerator selGen) {
1022:                {
1023:                    String html = selGen.generateSelectionScript(jjsOptions
1024:                            .getOutput().shouldMinimize(), false);
1025:                    String fn = module.getName() + ".nocache.js";
1026:                    File selectionFile = new File(outDir, fn);
1027:                    Util.writeStringAsFile(selectionFile, html);
1028:                    String msg = "Compilation selection script written to "
1029:                            + selectionFile.getAbsolutePath();
1030:                    logger.log(TreeLogger.TRACE, msg, null);
1031:                }
1032:                {
1033:                    String html = selGen.generateSelectionScript(jjsOptions
1034:                            .getOutput().shouldMinimize(), true);
1035:                    String fn = module.getName() + "-xs.nocache.js";
1036:                    File selectionFile = new File(outDir, fn);
1037:                    Util.writeStringAsFile(selectionFile, html);
1038:                    String msg = "Compilation selection script written to "
1039:                            + selectionFile.getAbsolutePath();
1040:                    logger.log(TreeLogger.TRACE, msg, null);
1041:                }
1042:            }
1043:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.