Compiler API
From OpenLaszlo
Here's a sketch of how to invoke the compiler. You can find code that does this in WEB-INF/lps/server/src/com/laszlosystems/compiler/Main.java.
The presentation server uses four caches:
- The application cache for compiled applications (swf files and their metadata)
- The media cache for transcoded media files
- The data cache for transcoded XML data documents
- The script compiler cache for compiled script fragments
When you invoke the application compiler directly, only the media cache and the script compiler cache are used. (The application cache is used by the Compilation Manager, which is a layer on top of the application compiler and which is bypassed in this scenario. The data cache is only used during application execution, for caching dynamic data requests.)
Create a new Compiler.
import com.laszlosystems.sc.ScriptCompiler;
import com.laszlosystems.sc.ScriptCompiler;
import com.laszlosystems.compiler.*;
Compiler compiler = new Compiler();
Configure the media and script compiler cache locations, and inject them into the Compiler instance and the ScriptCompiler global state, respectively. (For historical reasons, the cache reference injection is asymmetric.) Note: if you are invoking the compiler from another process while the LPS server is running, you will need to use different locations than the server uses, since the caches are synchronized through instances within the LPS process, and the server process and your process won't be able to synchronize on the same cache. I've made a location up at random, below. (And with os-specific filenames.)
String cacheDir = "c:/lps/caches/media";
CompilerMediaCache cache = new CompilerMediaCache(new File(cacheDir), new Properties());
compiler.setMediaCache(cache);
String scacheDir = "c:/lps/caches/sc";
ScriptCompiler.initScriptCompilerCache(new File(scacheDir), new Properties());
Turn on the "debug" compiler option. It defaults to false.
compiler.setProperty("debug", "true");
Perform the actual compilation:
File sourceFile = new File("test.lzx");
File objectFile = new File("test.swf");
try {
compiler.compile(sourceFile, objectFile, new Properties());
} catch (CompilationError e) {
System.err.println("Compilation errors: " + e.getMessage());
} catch (IOException e) {
System.err.println("Compilation errors: " + e.getMessage());
}
Compiler.compile() has the side effect of place or replacing objectFile by the swf file that results from compiling sourceFile. It does no dependency checking; the source file is always compiled. It does use the media cache and the script compiler cache, with the result that recompilation is faster than the initial compile, and that memory shrinks with each new application that is compiled. (The maximum caches sizes are configurable; we can go into that later.)
Note: if you are bypassing LZServlet then you'll want to set LPS home using LPS.setHome().
Compiler.compile() returns a Canvas object, also in com.laszlosystems.compiler. This return value is not used in the sample above. It contains metadata for the application. Canvas.getXML("") returns a String representation of an XML document that looks like this:
<canvas title="Laszlo Weather" bgcolor="#eaeaea" width="240" height="320"> <info size="397732" gz-size="162685" ...> <!-- ... --> </info> </canvas>
The title, bgcolor, width and height are gathered from the application source, and are always present in the XML metadata (they are filled in with the default values if they are not present in the source).
The <infoelement contains a summary of application size. Web developers are very concerned about download size; the size and gzipped size are reported on the compilation results page, and the content of the <infoelement is used to generate a size profiling page for size optimization.
If an application compiles with compilation warnings, these are embedded in the XML metadata. Either /canvas/warnings or /canvas/warnings/error can be used to test for the existance of compilation warnings. (We don't distinguish between warnings and nonfatal errors; both are represented as /canvas/warnings/error elements.) The text content of each warning is of the form "filename:lineno:colno: message".
<canvas title="Laszlo Weather" bgcolor="#eaeaea" width="240" height="320">
<info size="397732" gz-size="162685" ...>
<!-- ... -->
</info>
<warnings>
<error>test.lzx:2:12: element "badtag" not allowed in this context.
Check whether it is spelled correctly, and whether a class with this name exists.</error>
<br>
<error>test.lzx:3:19: element "anotherbadtag" not allowed in this context. Check whether it is spelled correctly, and whether a class with this name exists.</error>
</warnings>
</canvas>
As an example, the file lps/templates/app-console.xslt processes this XML and creates the HTML that you see displayed when you request an lzx file such as http://localhost/lps-2.2/demos/weather/weather.lzx.
If the file cannot be compiled, you don't get a Canvas (because the call to Compiler.compile() doesn't return). In this case, the metadata can be returned from the instance of CompilationError that is thrown. CompilationError.toXML() returns a string representation of the XML representation of this metadata, which looks like this:
<error>|test.lzx:4:7: Syntax error: the token "error" was not expected at this position.|</error>
If compilation warnings were detected before the fatal error was signalled, these are available as children of the document root element:
<error>|test.lzx:4:7: Syntax error: the token "error" was not expected at this position. <error>test.lzx:2:12: element "badtag" not allowed in this context. Check whether it is spelled correctly, and whether a class with this name exists.</error> <error>test.lzx:3:19: element "anotherbadtag" not allowed in this context. Check whether it is spelled correctly, and whether a class with this name exists.</error> </error>

