001: /* *****************************************************************************
002: * Compiler.java
003: * ****************************************************************************/
004:
005: /* J_LZ_COPYRIGHT_BEGIN *******************************************************
006: * Copyright 2001-2007 Laszlo Systems, Inc. All Rights Reserved. *
007: * Use is subject to license terms. *
008: * J_LZ_COPYRIGHT_END *********************************************************/
009:
010: package org.openlaszlo.compiler;
011:
012: import java.lang.Integer;
013: import java.io.*;
014: import java.text.ChoiceFormat;
015: import java.text.MessageFormat;
016: import java.util.*;
017: import org.jdom.*;
018: import org.openlaszlo.css.CSSHandler;
019: import org.openlaszlo.sc.ScriptCompiler;
020: import org.openlaszlo.utils.ChainedException;
021: import org.openlaszlo.utils.FileUtils;
022: import org.openlaszlo.utils.ListFormat;
023: import org.openlaszlo.server.LPS;
024: import org.apache.log4j.*;
025:
026: /**
027: * Compiles a Laszlo XML source file, and any files that it
028: * references, into an object file that can be executed on the client.
029: *
030: * The compiler parses the file into XML, and then gets an element
031: * compiler for each toplevel element.
032: */
033: public class Compiler {
034: /** Set this to log the modified schema. */
035: public static Logger SchemaLogger = Logger.getLogger("schema");
036:
037: public static List KNOWN_RUNTIMES = Arrays.asList(new String[] {
038: "swf7", "swf8", "swf9", "dhtml", "j2me", "svg", "null" });
039: public static List SCRIPT_RUNTIMES = Arrays.asList(new String[] {
040: "swf9", "dhtml", "j2me", "svg", "null" });
041: public static List SWF_RUNTIMES = Arrays.asList(new String[] {
042: "swf7", "swf8" });
043:
044: /** Called to resolve file references (<code>src</code>
045: * attributes).
046: */
047: protected FileResolver mFileResolver = FileResolver.DEFAULT_FILE_RESOLVER;
048:
049: /**
050: * CompilerMediaCache
051: */
052: protected CompilerMediaCache mMediaCache = null;
053:
054: /** See getProperties.
055: */
056: protected final Properties mProperties = new Properties();
057:
058: /** Logger
059: */
060: private static Logger mLogger = Logger.getLogger(Compiler.class);
061:
062: /**
063: * A <code>Compiler</code>'s <code>Properties</code> stores
064: * properties that affect the compilation.
065: *
066: * <table><tr><th>Name=default</th><th>Meaning</th></tr>
067: * <tr><td>trace.xml=false</td><td>Display XML that's compiled to
068: * script, and the script that it compiles to.</td></tr>
069: * <tr><td>debug=true</td><td>Add in debug features to the output.</td></tr>
070: * <tr><td>trace.fonts=false</td><td>Additional font traces.</td></tr>
071: * <tr><td>swf.frame.rate=30</td><td>Output SWF frame rate.</td></tr>
072: * <tr><td>default.text.height=12</td><td>Default text height for
073: * fonts.</td></tr>
074: * <tr><td>text.borders=false</td><td>Display text borders in the output SWF
075: * for debugging.</td></tr>
076: * </table>
077: *
078: * Properties that one part of the compiler sets for another part to read:
079: * <table><tr><th>Name=default</th><th>Meaning</th></tr>
080: * <tr><td>lzc_*</td><td>Source location values.</td></tr>
081: * </table>
082: *
083: * @return a <code>Properties</code> value
084: */
085: public String getProperty(String key) {
086: return mProperties.getProperty(key);
087: }
088:
089: public void setProperty(String key, String value) {
090: mProperties.setProperty(key, value);
091: }
092:
093: public FileResolver getFileResolver() {
094: return mFileResolver;
095: }
096:
097: /** Sets the file resolver for this compiler. The file resolver
098: * is used to resolve the names used in include directives to
099: * files.
100: * @param resolver a FileResolver
101: */
102: public void setFileResolver(FileResolver resolver) {
103: this .mFileResolver = resolver;
104: }
105:
106: /** Sets the media cache for this compiler.
107: * @param cache a CompilerMediaCache
108: */
109: public void setMediaCache(CompilerMediaCache cache) {
110: this .mMediaCache = cache;
111: }
112:
113: /** Create a CompilationEnvironment with the properties and
114: * FileResolver of this compiler.
115: */
116: public CompilationEnvironment makeCompilationEnvironment() {
117: return new CompilationEnvironment(mProperties, mFileResolver,
118: mMediaCache);
119: }
120:
121: /** Compiles <var>sourceFile</var> to <var>objectFile</var>. If
122: * compilation fails, <var>objectFile</var> is deleted.
123: *
124: * @param sourceFile source File
125: * @param objectFile a File to place object code in
126: * @param url request url, ignore if null
127: * @throws CompilationError if an error occurs
128: * @throws IOException if an error occurs
129: */
130: public Canvas compile(File sourceFile, File objectFile, String url)
131: throws CompilationError, IOException {
132: Properties props = new Properties();
133: return compile(sourceFile, objectFile, props);
134: }
135:
136: public static String getObjectFileExtensionForRuntime(String runtime) {
137: String ext = SCRIPT_RUNTIMES.contains(runtime) ? ".js"
138: : ".lzr=" + runtime + ".swf";
139: return ext;
140: }
141:
142: /** Compiles <var>sourceFile</var> to <var>objectFile</var>. If
143: * compilation fails, <var>objectFile</var> is deleted.
144: *
145: * @param sourceFile source File
146: * @param objectFile a File to place object code in
147: * @param props parameters for the compile
148: * @throws CompilationError if an error occurs
149: * @throws IOException if an error occurs
150:
151: * The PROPS parameters for the compile may include
152: * <ul>
153: * <li> url, optional, ignore if null
154: * <li> debug := "true" | "false" include debugger
155: * <li> logdebug := "true" | "false" makes debug.write() calls get logged to server
156: * </ul>
157: */
158: public Canvas compile(File sourceFile, File objectFile,
159: Properties props) throws CompilationError, IOException {
160: FileUtils.makeFileAndParentDirs(objectFile);
161:
162: // Compile to a byte-array, and write out to objectFile, and
163: // write a copy into sourceFile.[swf|js] if this is a serverless deployment.
164: CompilationEnvironment env = makeCompilationEnvironment();
165: ByteArrayOutputStream bstream = new ByteArrayOutputStream();
166: OutputStream ostream = new FileOutputStream(objectFile);
167: env.setObjectFile(objectFile);
168:
169: boolean success = false;
170: try {
171: Canvas canvas = compile(sourceFile, bstream, props, env);
172: bstream.writeTo(ostream);
173: ostream.close();
174:
175: // If the app is serverless, write out a .lzx.swf file when compiling
176: if (canvas != null && !canvas.isProxied()) {
177:
178: // Create a foo.lzx.[js|swf] serverless deployment file for sourcefile foo.lzx
179: String runtime = props
180: .getProperty(CompilationEnvironment.RUNTIME_PROPERTY);
181: String soloExtension = getObjectFileExtensionForRuntime(runtime);
182:
183: OutputStream fostream = null;
184: try {
185: File deploymentFile = new File(sourceFile
186: + soloExtension);
187: fostream = new FileOutputStream(deploymentFile);
188: bstream.writeTo(fostream);
189: } finally {
190: if (fostream != null) {
191: fostream.close();
192: }
193: }
194: }
195: success = true;
196: return canvas;
197: } catch (java.lang.OutOfMemoryError e) {
198: // The runtime gc is necessary in order for subsequent
199: // compiles to succeed. The System gc is for good luck.
200: System.gc();
201: Runtime.getRuntime().gc();
202: throw new CompilationError("out of memory");
203: } finally {
204: if (!success) {
205: ostream.close();
206: objectFile.delete();
207: }
208: }
209: }
210:
211: ObjectWriter createObjectWriter(Properties props,
212: OutputStream ostr, CompilationEnvironment env, Element root) {
213: if ("false".equals(props.getProperty(env.LINK_PROPERTY))) {
214: return new LibraryWriter(props, ostr, mMediaCache, true,
215: env, root);
216: }
217:
218: String runtime = props.getProperty(env.RUNTIME_PROPERTY);
219: // Must be kept in sync with server/sc/lzsc.py compile
220: if ("null".equals(runtime)) {
221: return new NullWriter(props, ostr, mMediaCache, true, env);
222: } else if (SCRIPT_RUNTIMES.contains(runtime)) {
223: return new DHTMLWriter(props, ostr, mMediaCache, true, env);
224: } else {
225: return new SWFWriter(props, ostr, mMediaCache, true, env);
226: }
227: }
228:
229: /**
230: * Compiles <var>file</var>, and write the bytes to
231: * a stream.
232: *
233: * @param file a <code>File</code> value
234: * @param ostr an <code>OutputStream</code> value
235: * @param props parameters for the compilation
236: * @exception CompilationError if an error occurs
237: * @exception IOException if an error occurs
238: *
239: * The parameters currently being looked for in the PROPS arg
240: * are "debug", "logdebug", "profile", "krank"
241: *
242: */
243:
244: public Canvas compile(File file, OutputStream ostr,
245: Properties props, CompilationEnvironment env)
246: throws CompilationError, IOException {
247: mLogger.info("compiling " + file + "...");
248:
249: CompilationErrorHandler errors = env.getErrorHandler();
250: env.setApplicationFile(file);
251:
252: // Copy target properties (debug, logdebug, profile, krank,
253: // runtime) from props arg to CompilationEnvironment
254: String runtime = props.getProperty(env.RUNTIME_PROPERTY);
255: boolean linking = (!"false".equals(env
256: .getProperty(CompilationEnvironment.LINK_PROPERTY)));
257:
258: if (runtime != null) {
259: mLogger.info("canvas compiler compiling runtime = "
260: + runtime);
261: env.setProperty(env.RUNTIME_PROPERTY, runtime);
262: if (!KNOWN_RUNTIMES.contains(runtime)) {
263: List runtimes = new Vector();
264: for (Iterator iter = KNOWN_RUNTIMES.iterator(); iter
265: .hasNext();) {
266: runtimes.add("\"" + iter.next() + "\"");
267: }
268:
269: throw new CompilationError(
270: MessageFormat
271: .format(
272: "Request for unknown runtime: The \"lzr\" query parameter has the value \"{0}\". It must be {1}{2}.",
273: new String[] {
274: runtime,
275: new ChoiceFormat(
276: "1#| 2#either | 2<one of ")
277: .format(runtimes
278: .size()),
279: new ListFormat("or")
280: .format(runtimes) }));
281: }
282: }
283:
284: String proxied = props
285: .getProperty(CompilationEnvironment.PROXIED_PROPERTY);
286: mLogger.debug(
287: /* (non-Javadoc)
288: * @i18n.test
289: * @org-mes="looking for lzproxied, props= " + p[0]
290: */
291: org.openlaszlo.i18n.LaszloMessages.getMessage(Compiler.class
292: .getName(), "051018-257", new Object[] { props
293: .toString() }));
294: if (proxied != null) {
295: mLogger.debug(
296: /* (non-Javadoc)
297: * @i18n.test
298: * @org-mes="setting lzproxied to " + p[0]
299: */
300: org.openlaszlo.i18n.LaszloMessages.getMessage(
301: Compiler.class.getName(), "051018-266",
302: new Object[] { proxied }));
303: env.setProperty(CompilationEnvironment.PROXIED_PROPERTY,
304: proxied);
305: }
306:
307: String debug = props
308: .getProperty(CompilationEnvironment.DEBUG_PROPERTY);
309: if (debug != null) {
310: env.setProperty(CompilationEnvironment.DEBUG_PROPERTY,
311: debug);
312: }
313:
314: String backtrace = props
315: .getProperty(CompilationEnvironment.BACKTRACE_PROPERTY);
316: if (backtrace != null) {
317: if ("true".equals(backtrace)) {
318: env.setProperty(CompilationEnvironment.DEBUG_PROPERTY,
319: "true");
320: }
321: env.setProperty(CompilationEnvironment.BACKTRACE_PROPERTY,
322: backtrace);
323: }
324:
325: String profile = props
326: .getProperty(CompilationEnvironment.PROFILE_PROPERTY);
327: if (profile != null) {
328: env.setProperty(CompilationEnvironment.PROFILE_PROPERTY,
329: profile);
330: }
331:
332: String logdebug = props
333: .getProperty(CompilationEnvironment.LOGDEBUG_PROPERTY);
334: if (logdebug != null) {
335: env.setProperty(CompilationEnvironment.LOGDEBUG_PROPERTY,
336: logdebug);
337: }
338:
339: String sourcelocators = props
340: .getProperty(CompilationEnvironment.SOURCELOCATOR_PROPERTY);
341: if (sourcelocators != null) {
342: env.setProperty(
343: CompilationEnvironment.SOURCELOCATOR_PROPERTY,
344: sourcelocators);
345: }
346:
347: try {
348: mLogger.debug(
349: /* (non-Javadoc)
350: * @i18n.test
351: * @org-mes="Parsing " + p[0]
352: */
353: org.openlaszlo.i18n.LaszloMessages.getMessage(
354: Compiler.class.getName(), "051018-303",
355: new Object[] { file.getAbsolutePath() }));
356:
357: Document doc = env.getParser().parse(file, env);
358: Element root = doc.getRootElement();
359:
360: // Override passed in runtime target properties with the
361: // canvas values.
362: if ("true".equals(root.getAttributeValue("debug"))) {
363: env.setProperty(CompilationEnvironment.DEBUG_PROPERTY,
364: true);
365: }
366:
367: if ("true".equals(root.getAttributeValue("profile"))) {
368: env.setProperty(
369: CompilationEnvironment.PROFILE_PROPERTY, true);
370: }
371:
372: // cssfile cannot be set in the canvas tag
373: String cssfile = props
374: .getProperty(CompilationEnvironment.CSSFILE_PROPERTY);
375: if (cssfile != null) {
376: mLogger.info("Got cssfile named: " + cssfile);
377: cssfile = root.getAttributeValue("cssfile");
378: throw new CompilationError(
379: "cssfile attribute of canvas is no longer supported. Use <stylesheet> instead.");
380:
381: }
382:
383: mLogger.debug("Making a writer...");
384:
385: // Initialize the schema from the base LFC interface file
386: try {
387: env.getSchema().loadSchema(env);
388: } catch (org.jdom.JDOMException e) {
389: throw new ChainedException(e);
390: }
391: ViewSchema schema = env.getSchema();
392: Set externalLibraries = null;
393: // If we are not linking, then we consider all external
394: // files to have already been imported.
395: if (!linking) {
396: externalLibraries = env.getImportedLibraryFiles();
397: }
398: if (root.getName().intern() != (linking ? "canvas"
399: : "library")) {
400: throw new CompilationError(
401: /* (non-Javadoc)
402: * @i18n.test
403: * @org-mes="invalid root element type: " + p[0]
404: */
405: org.openlaszlo.i18n.LaszloMessages.getMessage(
406: Compiler.class.getName(), "051018-357",
407: new Object[] { root.getName() }));
408: }
409: Compiler.updateRootSchema(root, env, schema,
410: externalLibraries);
411: Properties nprops = (Properties) env.getProperties()
412: .clone();
413: Map compileTimeConstants = new HashMap();
414: compileTimeConstants
415: .put(
416: "$debug",
417: new Boolean(
418: env
419: .getBooleanProperty(CompilationEnvironment.DEBUG_PROPERTY)));
420: compileTimeConstants
421: .put(
422: "$profile",
423: new Boolean(
424: env
425: .getBooleanProperty(CompilationEnvironment.PROFILE_PROPERTY)));
426: compileTimeConstants
427: .put(
428: "$backtrace",
429: new Boolean(
430: env
431: .getBooleanProperty(CompilationEnvironment.BACKTRACE_PROPERTY)));
432:
433: runtime = env.getProperty(env.RUNTIME_PROPERTY);
434:
435: // Must be kept in sync with server/sc/lzsc.py main
436: compileTimeConstants.put("$runtime", runtime);
437: compileTimeConstants.put("$swf7", Boolean.valueOf("swf7"
438: .equals(runtime)));
439: compileTimeConstants.put("$swf8", Boolean.valueOf("swf8"
440: .equals(runtime)));
441: compileTimeConstants.put("$as2", Boolean.valueOf(Arrays
442: .asList(new String[] { "swf7", "swf8", "swf9" })
443: .contains(runtime)));
444: compileTimeConstants.put("$swf9", Boolean.valueOf("swf9"
445: .equals(runtime)));
446: compileTimeConstants
447: .put("$as3", Boolean.valueOf(Arrays.asList(
448: new String[] { "swf9" }).contains(runtime)));
449: compileTimeConstants.put("$dhtml", Boolean.valueOf("dhtml"
450: .equals(runtime)));
451: compileTimeConstants.put("$j2me", Boolean.valueOf("j2me"
452: .equals(runtime)));
453: compileTimeConstants.put("$svg", Boolean.valueOf("svg"
454: .equals(runtime)));
455: compileTimeConstants.put("$js1", Boolean.valueOf(Arrays
456: .asList(new String[] { "dhtml", "j2me", "svg" })
457: .contains(runtime)));
458:
459: // [todo: 2006-04-17 hqm] These compileTimeConstants will be used by the script compiler
460: // at compile time, but they won't be emitted into the object code for user apps. Only
461: // the compiled LFC emits code which defines these constants. We need to have some
462: // better way to ensure that the LFC's constants values match the app code's.
463: nprops.put("compileTimeConstants", compileTimeConstants);
464:
465: ObjectWriter writer = createObjectWriter(nprops, ostr, env,
466: root);
467:
468: env.setObjectWriter(writer);
469:
470: mLogger
471: .debug("new env..."
472: + env.getProperties().toString());
473:
474: processCompilerInstructions(root, env);
475: compileElement(root, env);
476: if (linking) {
477: ViewCompiler.checkUnresolvedResourceReferences(env);
478: }
479: mLogger.debug("done...");
480: // This isn't in a finally clause, because it won't generally
481: // succeed if an error occurs.
482: writer.close();
483:
484: Canvas canvas = env.getCanvas();
485: if (!errors.isEmpty()) {
486: if (canvas != null) {
487: canvas.setCompilationWarningText(errors
488: .toCompilationError().getMessage());
489: canvas.setCompilationWarningXML(errors.toXML());
490: }
491: System.err.println(errors.toCompilationError()
492: .getMessage());
493: }
494: if (canvas != null) {
495: // set file path (relative to webapp) in canvas
496: canvas.setFilePath(FileUtils.relativePath(file, LPS
497: .HOME()));
498: }
499: mLogger.info("done");
500: return canvas;
501: } catch (CompilationError e) {
502: // TBD: e.initPathname(file.getPath());
503: e.attachErrors(errors.getErrors());
504: throw e;
505: //errors.addError(new CompilationError(e.getMessage() + "; compilation aborted"));
506: //throw errors.toCompilationError();
507: } catch (org.openlaszlo.xml.internal.MissingAttributeException e) {
508: /* The validator will have caught this, but if we simply
509: * pass the error through, the vaildation warnings will
510: * never be printed. Create a new message that includes
511: * them so that we get the source information. */
512: errors.addError(new CompilationError(
513: /* (non-Javadoc)
514: * @i18n.test
515: * @org-mes=p[0] + "; compilation aborted"
516: */
517: org.openlaszlo.i18n.LaszloMessages.getMessage(
518: Compiler.class.getName(), "051018-399",
519: new Object[] { e.getMessage() })));
520: throw errors.toCompilationError();
521: }
522: }
523:
524: public void compileAndWriteToSWF(String script, String seqnum,
525: OutputStream out, String runtime) {
526: try {
527: CompilationEnvironment env = makeCompilationEnvironment();
528: env
529: .setProperty(CompilationEnvironment.DEBUG_PROPERTY,
530: true);
531: Properties props = (Properties) env.getProperties().clone();
532: env.setProperty(env.RUNTIME_PROPERTY, runtime);
533: byte[] action;
534:
535: // Try compiling as an expression first. If that fails,
536: // compile as sequence of statements. If that fails too,
537: // report the parse error.
538: try {
539: String prog;
540: if (seqnum == null) {
541: prog = "(function () {\n"
542: + " #pragma 'scriptElement'\n"
543: + "_level0.Debug.displayResult(\n" + script
544: + "\n" + ");\n" + "}());\n";
545: } else {
546: // it's a remote debug request, send a response to client
547: prog = "(function () {\n"
548: + " #pragma 'scriptElement'\n"
549: + "_level0.Debug.displayResult(\n"
550: + " _level0.__LzDebug.sockWriteAsXML(\n"
551: + script + "," + seqnum + ");\n" + " );\n"
552: + "}());\n";
553: }
554: prog += "this._parent.loader.returnData( this._parent );";
555: action = ScriptCompiler.compileToByteArray(prog, props);
556: } catch (org.openlaszlo.sc.parser.ParseException e) {
557: try {
558: String wrapper = " (function () {\n"
559: + " #pragma 'scriptElement'\n"
560: + CompilerUtils.sourceLocationDirective(
561: null, new Integer(0),
562: new Integer(0))
563: + script
564: + "\n"
565: + " if (Debug.remoteDebug) { _level0.__LzDebug.sockWriteAsXML(true,"
566: + seqnum
567: + ");};\n"
568: + " }());\n"
569: + "this._parent.loader.returnData( this._parent )";
570: action = ScriptCompiler.compileToByteArray(wrapper,
571: props);
572: } catch (org.openlaszlo.sc.parser.ParseException e2) {
573: //mLogger.info("not stmt: " + e);
574: action = ScriptCompiler
575: .compileToByteArray(
576: "with(_level0) {Debug.__write("
577: + ScriptCompiler
578: .quote("Parse error: "
579: + e2
580: .getMessage())
581: + ")}\n"
582: + "this._parent.loader.returnData( this._parent )",
583: props);
584: }
585: }
586:
587: ScriptCompiler.writeScriptToStream(action, out, LPS
588: .getSWFVersionNum(runtime));
589: out.flush();
590: out.close();
591: } catch (IOException e) {
592: mLogger.info(
593: /* (non-Javadoc)
594: * @i18n.test
595: * @org-mes="error compiling/writing script: " + p[0] + " :" + p[1]
596: */
597: org.openlaszlo.i18n.LaszloMessages.getMessage(
598: Compiler.class.getName(), "051018-458",
599: new Object[] { script, e }));
600: }
601: }
602:
603: static ElementCompiler getElementCompiler(Element element,
604: CompilationEnvironment env) {
605: if (CanvasCompiler.isElement(element)) {
606: return new CanvasCompiler(env);
607: } else if (ImportCompiler.isElement(element)) {
608: return new ImportCompiler(env);
609: } else if (LibraryCompiler.isElement(element)) {
610: return new LibraryCompiler(env);
611: } else if (ScriptElementCompiler.isElement(element)) {
612: return new ScriptElementCompiler(env);
613: } else if (DataCompiler.isElement(element)) {
614: return new DataCompiler(env);
615: } else if (SecurityCompiler.isElement(element)) {
616: return new SecurityCompiler(env);
617: } else if (SplashCompiler.isElement(element)) {
618: return new SplashCompiler(env);
619: } else if (FontCompiler.isElement(element)) {
620: return new FontCompiler(env);
621: } else if (ResourceCompiler.isElement(element)) {
622: return new ResourceCompiler(env);
623: } else if (ClassCompiler.isElement(element)) {
624: return new ClassCompiler(env);
625: } else if (InterfaceCompiler.isElement(element)) {
626: return new InterfaceCompiler(env);
627: } else if (DebugCompiler.isElement(element)) {
628: return new DebugCompiler(env);
629: } else if (StyleSheetCompiler.isElement(element)) {
630: return new StyleSheetCompiler(env);
631: // The following test tests true for everything, so call
632: // it last.
633: } else if (ViewCompiler.isElement(element)) {
634: return new ViewCompiler(env);
635: } else {
636: throw new CompilationError("unknown tag: "
637: + element.getName(), element);
638: }
639: }
640:
641: /**
642: * Compile an XML element within the compilation environment.
643: * Helper function for compile.
644: *
645: * @param element an <code>Element</code> value
646: * @param env a <code>CompilationEnvironment</code> value
647: * @exception CompilationError if an error occurs
648: */
649: protected static void compileElement(Element element,
650: CompilationEnvironment env) throws CompilationError {
651: if (element.getAttributeValue("disabled") != null
652: && element.getAttributeValue("disabled").intern() == "true") {
653: return;
654: }
655: try {
656: ElementCompiler compiler = getElementCompiler(element, env);
657: mLogger.debug(
658: /* (non-Javadoc)
659: * @i18n.test
660: * @org-mes="compiling element with " + p[0]
661: */
662: org.openlaszlo.i18n.LaszloMessages.getMessage(
663: Compiler.class.getName(), "051018-526",
664: new Object[] { compiler.getClass().toString() }));
665: compiler.compile(element);
666: } catch (CompilationError e) {
667: // todo: wrap instead
668: if (e.getElement() == null && e.getPathname() == null) {
669: e.initElement(element);
670: }
671: throw e;
672: }
673: }
674:
675: static void updateRootSchema(Element root,
676: CompilationEnvironment env, ViewSchema schema,
677: Set externalLibraries) {
678: ElementCompiler ecompiler = getElementCompiler(root, env);
679: if (!(ecompiler instanceof ToplevelCompiler)) {
680: throw new CompilationError(
681: /* (non-Javadoc)
682: * @i18n.test
683: * @org-mes="invalid root element type: " + p[0]
684: */
685: org.openlaszlo.i18n.LaszloMessages.getMessage(
686: Compiler.class.getName(), "051018-357",
687: new Object[] { root.getName() }));
688: }
689: ToplevelCompiler tlc = (ToplevelCompiler) ecompiler;
690:
691: Set visited = new HashSet();
692: // Update schema for auto-includes
693: // Note: this call does _not_ share visited with the update
694: // calls intentionally.
695: for (Iterator iter = tlc.getLibraries(env, root, null,
696: externalLibraries, new HashSet()).iterator(); iter
697: .hasNext();) {
698: File library = (File) iter.next();
699: Compiler.updateSchemaFromLibrary(library, env, schema,
700: visited);
701: }
702: tlc.updateSchema(root, schema, visited);
703: }
704:
705: static void updateSchema(Element element,
706: CompilationEnvironment env, ViewSchema schema, Set visited) {
707: getElementCompiler(element, env).updateSchema(element, schema,
708: visited);
709: }
710:
711: static void importLibrary(File file, CompilationEnvironment env) {
712: Element root = LibraryCompiler.resolveLibraryElement(file, env,
713: env.getImportedLibraryFiles());
714: if (root != null) {
715: compileElement(root, env);
716: }
717: }
718:
719: static void updateSchemaFromLibrary(File file,
720: CompilationEnvironment env, ViewSchema schema, Set visited) {
721: Element root = LibraryCompiler.resolveLibraryElement(file, env,
722: visited);
723: if (root != null) {
724: Compiler.updateSchema(root, env, schema, visited);
725: }
726: }
727:
728: protected void processCompilerInstructions(Element element,
729: CompilationEnvironment env) {
730: for (Iterator iter = element.getContent().iterator(); iter
731: .hasNext();) {
732: ProcessingInstruction pi;
733: try {
734: pi = (ProcessingInstruction) iter.next();
735: } catch (ClassCastException e) {
736: continue;
737: }
738: if (pi.getTarget().equals("lzc"))
739: processCompilerInstruction(env, pi);
740: }
741: }
742:
743: protected void processCompilerInstruction(
744: CompilationEnvironment env, ProcessingInstruction pi) {
745: if (pi.getPseudoAttributeValue("class") != null)
746: processClassInstruction(env, pi
747: .getPseudoAttributeValue("class"), pi);
748: if (pi.getPseudoAttributeValue("classes") != null) {
749: for (Iterator iter = Arrays
750: .asList(
751: pi.getPseudoAttributeValue("classes")
752: .split("\\s+")).iterator(); iter
753: .hasNext();) {
754: processClassInstruction(env, (String) iter.next(), pi);
755: }
756: }
757: }
758:
759: protected void processClassInstruction(CompilationEnvironment env,
760: String className, ProcessingInstruction pi) {
761: String inlineString = pi.getPseudoAttributeValue("inline-only");
762: if (inlineString != null) {
763: boolean inline = Boolean.valueOf(inlineString)
764: .booleanValue();
765: ClassModel classModel = env.getSchema().getClassModel(
766: className);
767: if (classModel == null) {
768: env.warn(
769: /* (non-Javadoc)
770: * @i18n.test
771: * @org-mes="A processor instruction refers to a class named \"" + p[0] + "\". No class with this name exists."
772: */
773: org.openlaszlo.i18n.LaszloMessages.getMessage(
774: Compiler.class.getName(), "051018-603",
775: new Object[] { className }));
776: return;
777: }
778: classModel.setInline(inline);
779: }
780: }
781: }
|