KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > openlaszlo > compiler > CompilationEnvironment


1 /* ****************************************************************************
2  * CompilationEnvironment.java
3 * ****************************************************************************/

4
5 /* J_LZ_COPYRIGHT_BEGIN *******************************************************
6 * Copyright 2001-2004 Laszlo Systems, Inc. All Rights Reserved. *
7 * Use is subject to license terms. *
8 * J_LZ_COPYRIGHT_END *********************************************************/

9
10 package org.openlaszlo.compiler;
11
12 import java.io.*;
13 import java.util.*;
14 import org.jdom.Element;
15 import org.apache.log4j.*;
16 import org.openlaszlo.server.LPS;
17 import org.openlaszlo.utils.ChainedException;
18 import org.openlaszlo.utils.ComparisonMap;
19 import org.openlaszlo.utils.FileUtils;
20 import org.openlaszlo.xml.internal.XMLUtils;
21
22 /** Encapsulates all the context that script compilation needs to
23  * refer to. Instances of this class are threaded through the calls
24  * to instances of CompilerNode.
25  *
26  * Also contains utility functions for compiling to a file.
27  */

28 public class CompilationEnvironment {
29     private final Properties mProperties;
30     public static final String JavaDoc SWFVERSION_PROPERTY = "runtime";
31     static final String JavaDoc PROXIED_PROPERTY = "lzproxied";
32     static final String JavaDoc DEBUG_PROPERTY = "debug";
33     static final String JavaDoc PROFILE_PROPERTY = "profile";
34     static final String JavaDoc KRANK_PROPERTY = "krank";
35     static final String JavaDoc VALIDATE_PROPERTY = "validate";
36     // Log all debug.write messages back to the server
37
static final String JavaDoc LOGDEBUG_PROPERTY = "logdebug";
38     public static final String JavaDoc REMOTEDEBUG_PROPERTY = "remotedebug";
39     static final String JavaDoc EMBEDFONTS_PROPERTY = "embedfonts";
40     static final String JavaDoc SOURCELOCATOR_PROPERTY = "sourcelocators";
41     public static final String JavaDoc USER_DEBUG_WINDOW = "userdebugwindow";
42
43
44     /** The root file being compiled. This is used to resolve
45      * relative pathnames. */

46     protected File mApplicationFile = null;
47
48     final SymbolGenerator methodNameGenerator;
49
50     /** Output is written here.
51      *
52      * When we support multiple targets, this can be generalized to an
53      * interface that SWFWriter implements.*/

54     private SWFWriter mSWFWriter;
55     /** Main program output when generating a loadable
56      * library. Otherwise same as mSWFWriter */

57     private SWFWriter mMainSWFWriter;
58
59     private final FileResolver mFileResolver;
60
61     private final CompilationErrorHandler mCompilerErrors =
62         new CompilationErrorHandler();
63
64     /** A ViewSchema object, to allow adding of user defined classes
65      * during compilation.
66      */

67     private final ViewSchema mSchema;
68
69     /**
70      * CompilerMediaCache
71      */

72     private CompilerMediaCache mMediaCache = null;
73
74     /** A cache of a compiled validator */
75     private org.iso_relax.verifier.Verifier cachedVerifier = null;
76
77     /** {canonical filenames} for libraries that have been imported;
78      * used to prevent recursive processing and including the same
79      * library more than once. */

80     private Set mImportedLibraryFiles = new HashSet();
81
82     /** {canonical filenames} for loadable libraries that have been imported;
83          this is the set of all files included by loadable libraries (<import>'ed).
84          We keep this so we can issue a warning if two different loadable libraries
85          statically include the same library file.
86     */

87     private Map mLoadableImportedLibraryFiles = new HashMap();
88
89     /** Keep track of all named resources, so we can check if a view references a defined resource. */
90     private Set mResourceNames = new HashSet();
91
92     private final Parser mParser;
93     private Canvas mCanvas = null;
94
95     /** Keep a list of assigned global id's, so we can warn when one
96      * is redefined */

97     // TODO: [07-18-03 hqm] We will compare all id's case
98
// insensitively (using ComparisonMap), because actionscript is
99
// not case sensitive. But in the future, we should preserve
100
// case.
101
private final Map idTable = new ComparisonMap();
102
103     /** Holds a set of unresolved references to resources, so we can
104         check for undefined (possibly forward) references after all
105         app sources have been parsed.
106         Map contains resource-id => Element
107     */

108     private Map resourceReferences = new HashMap();
109
110     /** Cache of the FontInfo information for each class. Computed by
111         ViewCompiler walking a class' superclass chain from the base
112         class.
113     */

114     private HashMap classFontInfoTable = new HashMap();
115     private FontInfo mDefaultFontInfo;
116
117     /** Default text view width */
118     private static boolean mDefaultTextWidthInitialized = false;
119     private static int mDefaultTextWidth = 100;
120
121     /** Default SWF version to compile to */
122     private String JavaDoc mDefaultSWFVersion = LPS.getProperty("compiler.runtime.default", "swf6");
123
124     /** Constructs an instance.
125      * @param properties compilation properties
126      * @param writer output is sent here
127      */

128     CompilationEnvironment(Properties properties, FileResolver resolver, CompilerMediaCache mcache) {
129         // Use a local symbol generator so that we recycle method
130
// names for each new view, to keep the constant pool small.
131
this.methodNameGenerator = new SymbolGenerator("$m");
132         this.mSchema = new ViewSchema();
133         // lzc depends on the properties being shared, because it sets
134
// them after creating the environment
135
this.mProperties = properties;
136         this.mFileResolver = resolver;
137         this.mParser = new Parser();
138         this.mParser.setResolver(resolver);
139         this.mMediaCache = mcache;
140         // Default property values
141
this.setProperty(VALIDATE_PROPERTY, true);
142     }
143
144     /** Copy fields from an existing CompilationEnvironment.
145      */

146     CompilationEnvironment(CompilationEnvironment srcEnv) {
147         // Need to share name generator so we don't create non-unique
148
// unique names!
149
this.methodNameGenerator = srcEnv.methodNameGenerator;
150         this.mProperties = new Properties(srcEnv.getProperties());
151         this.mFileResolver = srcEnv.getFileResolver();
152         this.mParser = new Parser();
153         this.mParser.setResolver(this.mFileResolver);
154         // Default property values
155
this.setProperty(VALIDATE_PROPERTY, true);
156         this.mSchema = srcEnv.getSchema();
157         this.mCanvas = srcEnv.getCanvas();
158
159         this.mImportedLibraryFiles = new HashSet(srcEnv.getImportedLibraryFiles());
160         this.mLoadableImportedLibraryFiles = srcEnv.getLoadableImportedLibraryFiles();
161         this.mResourceNames = srcEnv.getResourceNames();
162     }
163     
164     /** Use this constructor for unit testing. The Compiler uses the
165      * constructor that takes a FileResolver. */

166     public CompilationEnvironment() {
167         this(new Properties(), FileResolver.DEFAULT_FILE_RESOLVER, null);
168     }
169     
170     void setApplicationFile(File file) {
171         mApplicationFile = file;
172         mCompilerErrors.setFileBase(file.getParent());
173         if (file.getParent() == null) {
174             mParser.basePathnames.add(0, "");
175         } else {
176             mParser.basePathnames.add(0, file.getParent());
177         }
178         // TODO: [12-26-2002 ows] Consolidate this list with the one
179
// in FileResolver.
180
mParser.basePathnames.add(LPS.getComponentsDirectory());
181         mParser.basePathnames.add(LPS.getFontDirectory());
182         mParser.basePathnames.add(LPS.getLFCDirectory());
183     }
184
185     // For an app named /path/to/myapp.lzx, returns /path/to/build/myapp
186
public String JavaDoc getLibPrefix() {
187         File appfile = getApplicationFile();
188         String JavaDoc appname = appfile.getName();
189
190         String JavaDoc basename = FileUtils.getBase(appname);
191
192         String JavaDoc parent = appfile.getParent();
193         if (parent == null) {
194             parent = ".";
195         }
196
197         String JavaDoc path = parent + "/" + "build" + "/" + basename;
198         return path;
199     }
200
201     // For an app named /path/to/myapp.lzx, returns build/myapp
202
public String JavaDoc getLibPrefixRelative() {
203         File appfile = getApplicationFile();
204         String JavaDoc appname = appfile.getName();
205
206         String JavaDoc basename = FileUtils.getBase(appname);
207
208         String JavaDoc path = "build" + "/" + basename;
209         return path;
210     }
211
212     public File getApplicationFile() {
213         return mApplicationFile;
214     }
215
216     public void setMediaCache(CompilerMediaCache cache) {
217         this.mMediaCache = cache;
218     }
219     public CompilerMediaCache getMediaCache() {
220         return this.mMediaCache;
221     }
222
223     public void setDefaultFontInfo(FontInfo fi) {
224         mDefaultFontInfo = fi;
225     }
226
227     public FontInfo getDefaultFontInfo() {
228         return mDefaultFontInfo;
229     }
230
231     /** Add canvas info. It is an error to call this before calling
232      * setCanvas (hand will currently result in a null reference
233      * exception). */

234     public void addClassFontInfo(String JavaDoc classname, FontInfo info) {
235         classFontInfoTable.put(classname, info);
236     }
237
238     public FontInfo getClassFontInfo(String JavaDoc classname) {
239         FontInfo cached = (FontInfo) classFontInfoTable.get(classname);
240         return cached;
241     }
242
243     public boolean getEmbedFonts() {
244         return this.getBooleanProperty(EMBEDFONTS_PROPERTY);
245     }
246
247     public void setEmbedFonts(boolean embed) {
248         this.setProperty(EMBEDFONTS_PROPERTY, embed);
249     }
250
251     public void setSWFWriter(SWFWriter writer) {
252         assert mSWFWriter == null;
253         this.mSWFWriter = writer;
254         this.mMainSWFWriter = writer;
255     }
256     
257     public void setMainSWFWriter(SWFWriter writer) {
258         assert mMainSWFWriter == null || mMainSWFWriter == mSWFWriter;
259         this.mMainSWFWriter = writer;
260     }
261     
262     public ViewSchema getSchema() {
263         return mSchema;
264     }
265
266     public static synchronized int getDefaultTextWidth() {
267         if (!mDefaultTextWidthInitialized) {
268             mDefaultTextWidthInitialized = true;
269             String JavaDoc dws = LPS.getProperty("compiler.defaultTextWidth", "100");
270             try {
271                 int dw = Integer.parseInt(dws);
272                 mDefaultTextWidth = dw;
273             } catch (NumberFormatException JavaDoc e) {
274                 Logger.getLogger(CompilationEnvironment.class)
275                     .error("could not parse property value for compiler.defaultTextWidth: " + dws);
276             }
277         }
278         return mDefaultTextWidth;
279     }
280
281     public CompilationErrorHandler getErrorHandler() {
282         return mCompilerErrors;
283     }
284
285     public void warn(CompilationError e) {
286         mCompilerErrors.addError(e);
287     }
288
289     public void warn(Throwable JavaDoc e, Element element) {
290         mCompilerErrors.addError(new CompilationError(element, e));
291     }
292
293     public void warn(String JavaDoc msg) {
294         warn(new CompilationError(msg));
295     }
296
297     public void warn(String JavaDoc msg, Element element) {
298         warn(new CompilationError(msg, element));
299     }
300
301     public Canvas getCanvas() {
302         return mCanvas;
303     }
304
305     public void setCanvas(Canvas canvas, String JavaDoc constructorScript) {
306         if (mCanvas != null)
307             throw new RuntimeException JavaDoc("canvas set twice");
308         mCanvas = canvas;
309         try {
310             getGenerator().setCanvas(canvas, constructorScript);
311         } catch (org.openlaszlo.sc.CompilerException e) {
312             throw new CompilationError(e);
313         }
314     }
315
316     public void addId(String JavaDoc name, Element e) {
317         idTable.put(name, e);
318     }
319
320     public Element getId(String JavaDoc name) {
321         return (Element) idTable.get(name);
322     }
323
324     public void addResourceReference(String JavaDoc name, Element elt) {
325         resourceReferences.put(name, elt);
326     }
327
328     public Map resourceReferences() {
329         return resourceReferences;
330     }
331
332
333     /** Returns the SWF writer that compilation within this
334      * environment writes to.
335      * @return the object writer
336      */

337     SWFWriter getGenerator() {
338         return mSWFWriter;
339     }
340
341     /** Returns the SWF writer for the main program compilation when
342      * compiling a loadable library.
343      * @return the object writer
344      */

345     SWFWriter getResourceGenerator() {
346         return mMainSWFWriter;
347     }
348
349     
350     /** Returns true if we're compiling a loadable library file.
351      * @return isLibrary
352      */

353     public boolean isImportLib() {
354         return mMainSWFWriter != mSWFWriter;
355     }
356
357     /** Returns the file resolver used in this environment.
358      * @return the object writer
359      */

360     FileResolver getFileResolver() {
361         return mFileResolver;
362     }
363
364     Set getImportedLibraryFiles() {
365         return mImportedLibraryFiles;
366     }
367
368     Map getLoadableImportedLibraryFiles() {
369         return mLoadableImportedLibraryFiles;
370     }
371
372     Set getResourceNames() {
373         return mResourceNames;
374     }
375
376     Parser getParser() {
377         return mParser;
378     }
379
380     /** Returns the Properties object used in this environment.
381      * @return the properties
382      */

383     Properties getProperties() {
384         return mProperties;
385     }
386
387     String JavaDoc getProperty(String JavaDoc name) {
388         return mProperties.getProperty(name);
389     }
390
391     String JavaDoc getProperty(String JavaDoc name, String JavaDoc defval) {
392         return mProperties.getProperty(name, defval);
393     }
394
395     void setProperty(String JavaDoc name, String JavaDoc value) {
396         mProperties.setProperty(name, value);
397     }
398
399     /** Return target Flash version (5, 6, ...) **/
400     public String JavaDoc getSWFVersion() {
401         return getProperty(SWFVERSION_PROPERTY, mDefaultSWFVersion);
402     }
403
404     public String JavaDoc getSWFVersion(String JavaDoc defaultVersion) {
405         return getProperty(SWFVERSION_PROPERTY, defaultVersion);
406     }
407
408     public int getSWFVersionInt() {
409         if ("swf6".equals(getSWFVersion())) {
410             return 6;
411         } else if ("swf7".equals(getSWFVersion())) {
412             return 7;
413         } else {
414             return 5;
415         }
416     }
417
418     boolean getBooleanProperty(String JavaDoc name) {
419         return "true".equals(mProperties.getProperty(name));
420     }
421
422     void setProperty(String JavaDoc name, boolean value) {
423         setProperty(name, value ? "true" : "false");
424     }
425
426     /** Compiles <var>script</var> to bytecodes, and adds them to the
427      * output file.
428      * @param script a script
429      */

430     void compileScript(String JavaDoc script) {
431         try {
432             int size = getGenerator().addScript(script);
433             Element info = new Element("block");
434             info.setAttribute("size", "" + size);
435             mCanvas.addInfo(info);
436         } catch (org.openlaszlo.sc.CompilerException e) {
437             throw new CompilationError(e);
438         }
439     }
440
441     void compileScript(String JavaDoc script, Element elt) {
442         try {
443             int size = getGenerator().addScript(script);
444             Element info = new Element("block");
445             info.setAttribute("pathname", Parser.getSourceMessagePathname(elt) );
446             info.setAttribute("lineno", ""+Parser.getSourceLocation(elt, Parser.LINENO));
447             info.setAttribute("tagname", elt.getName());
448             if (elt.getAttribute("id") != null)
449                 info.setAttribute("id", elt.getAttributeValue("id"));
450             if (elt.getAttribute("name") != null)
451                 info.setAttribute("name", elt.getAttributeValue("name"));
452             info.setAttribute("size", "" + size);
453             mCanvas.addInfo(info);
454         } catch (org.openlaszlo.sc.CompilerException e) {
455             throw new CompilationError(elt, e);
456         }
457     }
458
459     /** Holds the cached schema verifier */
460     org.iso_relax.verifier.Verifier getCachedVerifier () {
461         return cachedVerifier;
462     }
463
464     /** Use this to cache the schema verifier (call with null to flush the cache) */
465     void setCachedVerifier (org.iso_relax.verifier.Verifier verifier) {
466         cachedVerifier = verifier;
467     }
468
469     /**
470      * @return a unique name in the SWF
471      */

472     String JavaDoc uniqueName() {
473         return mSWFWriter.createName();
474     }
475
476     File resolve(String JavaDoc name, String JavaDoc base)
477         throws FileNotFoundException
478     {
479         return mFileResolver.resolve(name, base);
480     }
481
482     /** Resolve the value of the named attribute, relative to the
483      * source location of the element.
484      */

485     File resolveReference(Element element, String JavaDoc aname)
486         throws CompilationError
487     {
488         String JavaDoc base = new File(Parser.getSourcePathname(element)).getParent();
489         String JavaDoc href = XMLUtils.requireAttributeValue(element, aname);
490
491         try {
492             return mFileResolver.resolve(href, base);
493         } catch (FileNotFoundException e) {
494             throw new CompilationError(element, e);
495         }
496     }
497
498     /** Resolve the value of the parent node
499      */

500     File resolveParentReference(Element element)
501         throws CompilationError
502     {
503         return new File(Parser.getSourcePathname(element.getParent()));
504     }
505
506     /** Resolve the value of the "src" attribute, relative to the
507      * source location of the element.
508      */

509     File resolveReference(Element elt)
510         throws CompilationError
511     {
512         return resolveReference(elt, "src");
513     }
514
515     /** If the argument is a relative URL with no host, return an URL
516      * that resolves to the same address relative to the destDir as
517      * the argument does relative to sourceDir. Otherwise return the
518      * argument unchanged. */

519     static String JavaDoc adjustRelativeURL(String JavaDoc string, File sourceDir,
520                                     File destDir)
521     {
522         try {
523             java.net.URL JavaDoc url = new java.net.URL JavaDoc(string);
524             if (!url.getHost().equals("")) {
525                 // It's on a different host. Don't resolve it.
526
return string;
527             }
528             if (url.getPath().startsWith("/")) {
529                 // It's an absolute path. Don't resolve it.
530
return string;
531             }
532             String JavaDoc path;
533             try {
534                 path = FileUtils.adjustRelativePath(
535                     url.getPath(),
536                     FileUtils.toURLPath(sourceDir),
537                     FileUtils.toURLPath(destDir));
538             } catch (FileUtils.RelativizationError e) {
539                 throw new CompilationError(e);
540             }
541             if (url.getQuery() != null) {
542                 path += "?" + url.getQuery();
543             }
544             return new java.net.URL JavaDoc(
545                 url.getProtocol(), url.getHost(), url.getPort(), path)
546                 .toExternalForm();
547         } catch (java.net.MalformedURLException JavaDoc e) {
548             return string;
549         }
550     }
551
552     /** If the argument is a relative URL with no host, return an URL
553      * that resolves to the same address relative to the main source
554      * file as the argument does relative to the file that contains
555      * elt. Otherwise return the argument unchanged. */

556     String JavaDoc adjustRelativeURL(String JavaDoc string, Element elt) {
557         File appdir = mApplicationFile.getParentFile();
558         File localdir = new File(Parser.getSourcePathname(elt)).getParentFile();
559         if (appdir == null) {
560             appdir = new File(".");
561         }
562         if (localdir == null) {
563             localdir = new File(".");
564         }
565         return adjustRelativeURL(string, appdir, localdir);
566     }
567 }
568
Popular Tags