René Nyffenegger's collection of things on the web
René Nyffenegger on Oracle - Most wanted - Feedback -
 

Using the Laszlo framework as a standalone application

I am fascinated by Laszlo. On October 12th, I have already written on how to build Laszlo from sources. But I got also interested in the internal working of the framework because I want to use the framework with a standalone application, that is not as a web application.
First, I had to understand the framework. So, I copied the important code snippets of the framework here. I was not interested in any error handling, so I didn't copy it here. Also, I considered many code segments dealing with configuration of inferiour importance, so I skipped them as well.
However, I was top curious about the creation of SWF movies. Therefore, I kept everything wich I found necessary for SWF movies, particularly the ResponderSWF class.

A bird's view of the Laszlo framework

doGet: doGet is the starting point for every servlet. That's why this journey starts with Laszlo's doGet().
Laszlo's doGet() simply calls _doGet() (with a leading underscore). However, on its first invocation, it also calls initLPS.
servlets/LZServlet.java
public void doGet(HttpServletRequest req, HttpServletResponse res) {

  /* .... omitted ... */

  // Init LPS on first request
  if (requestID == 1) {
    if (initLPS(req, res) == false) {
        return;
    }
  }

  /* .... omitted ... */

  _doGet(req, res);
}
_doGet: _doGet is called twice for one Laszlo presentation request: once to create the html that embeds the generated flash movie and once to actually create the flash movie.
I don't care about the html part, from now on I only deal with the SWF part. The parameter lzt passed to getResponder is equal to swf, that is, getResponder() returnes a (cached) ResponderSWF.
servlets/LZServlet.java
private void _doGet(HttpServletRequest req, HttpServletResponse res) 
        throws IOException, ServletException {

  /* .... omitted ... */
  String lzt = getLZT(req);
  Responder lzres = getResponder(lzt);

  /* .... omitted ... */

  lzres.respond(req, res);
}
Responder.respond (more accuratly, a subtype's respond()) is called whenever a request is made against the Laszlo Presentation Server. respond() basically takes care of delivering the correct data to the browser. This method eventually calls respondImpl which is implemented in classes that are derived from Responder.
As ResponderSWF overrides respondImpl(), the call to respond on a ResponderSWF class will be routed to ResponderSWF.respondImpl().
public void respond(HttpServletRequest req, HttpServletResponse res)
{
  try {
    if ( ! mAllowRequest ) {
      /*  ... omitted ... */
    }

    // Don't include admin and connection reqs in stats.
    if ( mCollectStat &&
       ! mSTAT_adminClass.isInstance(this) &&
       ! mSTAT_connectClass.isInstance(this)) {

       /* ... omitted ... */

      try {
        respondImpl(req, res);
      } finally {
        /* ... omitted ... */
      }

    } else {
      /* ... omitted  ... */
    }

  } catch (CompilationError e) {
        respondWithError(res, e.getMessage(), 0); 
    } catch (IOException e) {
        respondWithException(res, e); 
    } catch (Exception e) {
        respondWithException(res, e); 
    }
}
servlets/LZServlet.java
String getLZT(HttpServletRequest req) {
  String lzt = req.getParameter("lzt");
  if (lzt == null || lzt.equals("")) 
    lzt = mDefaultRequestType;

  return lzt;
}
mDefaultRequestType is set to html. But then, it is newly assigned with app_console.
servlets/LZServlet.java
private static String mDefaultRequestType = "html";
initLPS is called on the first request made against the Laszlo presentation server. It basically initializes (hence its name) the LPS environment.
initLPS pre-creates the three responders ResponderSWF, ResponderMEDIA and ResponderDATA. The creation of ResponderSWF is somewhat interesting. Because ResponderSWF is inherited from ResponderCompile, the ResponderCompile's init() is called when ResponderSWF.init() is called. The init() creates a CompilationManager which is an imporant piece.
servlets/LZServlet.java
public boolean initLPS(HttpServletRequest req, HttpServletResponse res) {

  /* .... omitted ... */

  String lhome = getInitParameter("LPS_HOME");
  LPS.setHome(lhome);

  try {
      ResponderLOGCONFIG.configure(this);
  } catch (Exception e) {
      respondWithInitException(req, res, e);
      return false;
  }

  /* .... omitted ... */

  LPS.initialize();

  /* .... omitted ... */

  mProperties = LPS.getProperties();

  /* Precreating the three Responders ResponderSWF, ResponderMEDIA and ResponderDATA */
  String[] lzt = { "swf", "media", "data" };
  int i = 0;
  try {
    for (;i < lzt.length; i++) {
        if (getResponder(lzt[i]) == null) {
          /* .... omitted ... */
        }
      }
  } catch (Throwable e) {
     /* .... omitted ... */
      return false;
  }
  /* .... omitted ... */

  /* Sets mDefaultRequestType to app_console
  mDefaultRequestType = mProperties.getProperty(DEFAULT_REQUEST_TYPE, mDefaultRequestType);
}
LPS.initialize simply creates a new Configuration.
server/LPS.java.proto
public static void initialize() {
  configuration = new Configuration();
}
getResponder, found in the LZServlet class, is able to construct various Responder instances. The most important (for me) Responder type that it delivers, seems to be ResponderSWF. The parameter lzt defines the suffix of the wanted Responder. So, in order to get a ResponderSWF, the string "SWF" (case not important) must be passed.
When the desired Responder is created, init is called on the responder's instance. As mentioned, I am mostly interested in the ResponderSWF class, so the init here is hyperlinked with ResponderSWF.init().
servlets/LZServlet.java
private synchronized Responder getResponder(String lzt) 
    throws ServletException
{
  Responder lzres = (Responder) mResponderMap.get(lzt);

  String className = "com.laszlosystems.servlets.responders.Responder";

  if (lzres == null) {
    Class c = null;
    try {
        className += lzt.toUpperCase();
        c = Class.forName(className);
        lzres = (Responder)c.newInstance();
        lzres.init(lzt, getServletConfig(), mProperties);
        mResponderMap.put(lzt, lzres);
    } catch (InstantiationException e) {
        throw new ServletException("InstantiationException: " + e.getMessage());
    } catch (IllegalAccessException e) {
        throw new ServletException("IllegalAccessException: " + e.getMessage());
    } catch (ClassNotFoundException e) {
        try {
            lzres = TemplateResponder.getResponder(lzt);
        } catch (Throwable t) {
        }
        // The case where this returns null is handled by the caller.
        if (lzres == null) {
          /* .... omitted  .... */
        }
    } catch (Throwable e) {
       /* .... omitted  .... */
    }
  }
  return lzres;
}
It seems as though the ResponderSWF class does its main work through the respondImpl method.
servlets/responders/ResponderSWF.java
protected void respondImpl(String fileName, HttpServletRequest req, 
                           HttpServletResponse res)
{
  ServletOutputStream output = null;
  InputStream input = null;

  // Is this a request for an optimized file?
  boolean opt = fileName.endsWith(".lzo");

  // Compile the file and send it out
  try {

    output = res.getOutputStream();
    Properties props = initCMgrProperties(req);
    String encoding = props.getProperty(LZHttpUtils.CONTENT_ENCODING);

    if (opt) {
      /* .... omitted .... */
    } else {
        input = mCompMgr.getObjectStream(fileName, props);
    }

    long total = input.available();
    // Set length header before writing content.  WebSphere
    // requires this.
    // Ok to cast to int because SWF file must be a 32bit file
    res.setContentLength((int)total);
    res.setContentType(MimeType.SWF);
    if (encoding != null) {
        res.setHeader(LZHttpUtils.CONTENT_ENCODING, encoding);
    }

    try {
        FileUtils.send(input, output);
    } catch (FileUtils.StreamWritingException e) {
      /* ... omitted  ... */
    } catch (IOException e) {
      /* ... omitted  ... */
    } 

  } catch (Exception e) {
    /* ... omitted .... */
  } finally {
      FileUtils.close(input);
      FileUtils.close(output);
  }
}
The member mCompMgr, found in the ResponderCompile class is a reference to the CompilationManager. mCompMgr is initialized in ResponderCompile.init().
servlets/responders/ResponderCompile.java
protected static CompilationManager mCompMgr = null;
getObjectStream is the main entry point to the CompilationManager.
Note, the CompilationManager is created by ResponderCompile.init.
cm/CompilationManager.java
public synchronized InputStream getObjectStream(String pathname, Properties props)
    throws CompilationError, IOException
{
  /* ... omitted ... */
  return getItem(pathname, props).getStream();
}
CompilationManager.getItem
cm/CompilationManager.java
public synchronized Item getItem(String pathname, Properties props) 
  throws IOException {

  Serializable key = computeKey(pathname, props);
  String enc = props.getProperty(LZHttpUtils.CONTENT_ENCODING);
  boolean lockit = false;
  Item item = findItem(key, enc, lockit);
  // Set up the properties, for dependency checking
  Properties compilationProperties = (Properties) props.clone();
  if (!isItemUpToDate(item, pathname, compilationProperties)) {
      
    Properties props2 = (Properties) props.clone();
    if (enc == null || enc.equals("")) {
      props2.setProperty(LZHttpUtils.CONTENT_ENCODING, "gzip");
    } else {
      props2.setProperty(LZHttpUtils.CONTENT_ENCODING, "");
    }
    Serializable key2 = computeKey(pathname, props2);
    Item item2 = getItem(key2);
    if (item2 != null && isItemUpToDate(item2, pathname, props2)) {
      convertItemEncoding(item2, item, pathname, enc, compilationProperties);
    } else {
      compileItem(item, pathname, compilationProperties);
    }
  } 
  updateCache(item);
  return item;
}
CompilationManager.compileItem
cm/CompilationManager.java
public synchronized void compileItem(Item item, String pathname, 
        Properties compilationProperties)
    throws CompilationError
{
  File sourceFile = new File(mSourceDirectory, pathname);
  File objectFile = new File(item.getPathName());

  try {
    item.markDirty();

    com.laszlosystems.compiler.Compiler compiler =
        new com.laszlosystems.compiler.Compiler();

    for (java.util.Enumeration e = getProperties().propertyNames();
         e.hasMoreElements(); ) {
        String key = (String) e.nextElement();
        if (key.startsWith("compiler.")) {
            compiler.getProperties().setProperty(
                key.substring("compiler.".length()),
                getProperties().getProperty(key));
        }
    }

    DependencyTracker dependencyTracker =
        new DependencyTracker(compilationProperties);
    TrackingFileResolver resolver =
        new TrackingFileResolver(compiler.getFileResolver(),
                                 dependencyTracker);
    dependencyTracker.addFile(sourceFile);
    if (mLPSJarFile != null) {
        dependencyTracker.addFile(mLPSJarFile);
    }
    compiler.setFileResolver(resolver);
    compiler.setMediaCache(mMediaCache);

    Canvas canvas = null;

    File tempFile = null;
    FileInputStream tempFileStream = null;
    try {
      tempFile = File.createTempFile("lzc-", null);

      canvas = compiler.compile(sourceFile, tempFile, 
                                compilationProperties);

      tempFileStream = new FileInputStream(tempFile);

      item.update(tempFileStream);
      dependencyTracker.addFile(objectFile);
      String encoding = compilationProperties.getProperty(LZHttpUtils.CONTENT_ENCODING);
      // FIXME: [2003-07-21 bloch] the factoring of cm.CacheInfo and cache.CacheInfo
      // has never been right.  Someday, if there are more subclasses of Cache that
      // use the [gs]etMetaData methods, then this should really be fixed.  (bug #1778).
      CachedInfo info = new CachedInfo(dependencyTracker, canvas, encoding);
      item.getInfo().setLastModified(objectFile.lastModified());
      item.update(info);
      item.markClean();

      // Add security options for this application after compilation
      LPS.configuration.setApplicationOptions(FileUtils.relativePath(pathname, LPS.HOME()),
                                              canvas.getSecurityOptions());

    } finally {
      if (tempFileStream != null) {
          FileUtils.close(tempFileStream);
      }
      if (tempFile != null) {
          tempFile.delete();
      }

      // Cleanup now
      System.gc();
    }
  } catch (IOException ioe) {
      CompilationError e = new CompilationError(ioe);
      e.initPathname(sourceFile.getPath());
      throw e;
  }
}
This seems to be a crucial piece of code: it creates ResponderCompile.
servlets/responders/Responder.java.proto
    /** This needs to get called after the instantiation of the class object. */
public synchronized void init(String reqName, ServletConfig config, 
                                  Properties prop)
        throws ServletException, IOException
{
  mAllowRequest = 
      prop.getProperty("allowRequest" + reqName.toUpperCase(), 
                       mAllowRequestDefaultProperty).intern() == "true";

  if (! mIsInitialized) {

    mContext = config.getServletContext();
  
    try {

      /* .... omitted .... */

      mCompilerClass = 
          Class.forName("com.laszlosystems.servlets.responders.ResponderCompile");

    } catch (ClassNotFoundException e) {
        throw new ServletException(e.getMessage());
    }

    mEmitErrorHeader = 
        prop.getProperty("emitErrorHeader", "false").intern() == "true";
    mUseBogusErrorCode = 
        prop.getProperty("useBogusErrorCode", "false").intern() == "true";

    mCollectStat = 
        prop.getProperty("collectStat", "true").intern() == "true";

    mIsInitialized = true;
  }
}
ResponderSWF is derived from ResponderCompile. The init method creates a CompilerManager which can then be used by ResponderSWF.
/servlets/responders/ResponderCompile.java
synchronized public void init(String reqName, ServletConfig config, Properties prop)
    throws ServletException, IOException
{
  super.init(reqName, config, prop);

  // All compilation classes share cache directory and compilation manager.
  if (! mIsInitialized) {

    /* ... omitted  ... */


    // Initialize the Compilation Cache
    String cacheDir = config.getInitParameter("lps.cache.directory");
    if (cacheDir == null) {
        cacheDir = prop.getProperty("cache.directory");
    }
    if (cacheDir == null) {
        cacheDir = LPS.getWorkDirectory() + File.separator + "cache";
    }

    File cache = checkDirectory(cacheDir);

    if (mCompMgr == null) {
        mCompMgr = new CompilationManager(null, cache, prop);
    }

    if (mScriptCache == null) {
        String scacheDir = config.getInitParameter("lps.scache.directory");
        if (scacheDir == null) {
            scacheDir = prop.getProperty("scache.directory");
        }
        if (scacheDir == null) {
            scacheDir = LPS.getWorkDirectory() + File.separator + "scache";
        }
        File scache = checkDirectory(scacheDir);
        mScriptCache = ScriptCompiler.initScriptCompilerCache(scache, prop);
    }

    String cmOption = prop.getProperty("compMgrDependencyOption");
    if (cmOption!=null) {
        mCompMgr.setProperty("recompile", cmOption);
    }

    String lfcName = prop.getProperty("lfcLibraryName");
    if (lfcName != null) {
        mCompMgr.setProperty("compiler.lfcLibraryName", lfcName);
    }
  }
}
The constructor of the CompilationManager.
Copied out of Laszlo's JavaDoc: A CompilationManager is constructed with a source directory, where it looks for source files, and a cache directory, where it places compiled object files and cached (dependency) information. It can be instructed to always recompile files, never recompile them so long as they exist, or use dependency information that it creates during the course of a file compilation to determine whether a file is out of date. See the documentation for getProperty() for a description of how to select between these behaviors.
cm/CompilationManager.java
public CompilationManager(File sourceDirectory, File cacheDirectory, Properties props) 
  throws IOException {
  
  super("cache", cacheDirectory, props);

  this.mSourceDirectory = sourceDirectory;
  this.mCacheDirectory = cacheDirectory;
  try {
      cacheDirectory.mkdirs();
  } catch (SecurityException se) {
  }
  if (!cacheDirectory.exists()) {
      throw new FileNotFoundException(cacheDirectory.getAbsolutePath() + " does not exist");
  }
  if (!cacheDirectory.canRead()) {
      throw new IOException("can't read " + cacheDirectory.getAbsolutePath());
  }
  String p = cacheDirectory.getAbsolutePath() + File.separator + "media";
  this.mMediaCache = new CompilerMediaCache(new File(p), props);
  this.mProperties = props;

  String jd = LPS.getProperty("compMgr.lps.jar.dependency", "true");
  if ("true".equals(jd)) {
      mLPSJarFile = LPS.getLPSJarFile();
  }
}
The Compiler class has no explicit constructor defined.
Compiler.compile
compiler/Compiler.java
public Canvas compile(File sourceFile, File objectFile, Properties props)
    throws CompilationError, IOException
{
  FileUtils.makeFileAndParentDirs(objectFile);

  OutputStream ostream = new FileOutputStream(objectFile);
  boolean success = false;
  try {
    Canvas canvas = compile(sourceFile, ostream, props);
    ostream.close();
    success = true;
    return canvas;
  } catch (java.lang.OutOfMemoryError e) {
    // The runtime gc is necessary in order for subsequent
    // compiles to succeed.  The System gc is for good luck.
    System.gc();
    Runtime.getRuntime().gc();
    throw new CompilationError("out of memory");
  } finally {
    if (!success) {
      ostream.close();
      objectFile.delete();
    }
  }
}
Compiler.compile
compiler/Compiler.java
public Canvas compile(File file, OutputStream ostr, Properties props)
    throws CompilationError, IOException
{
  CompilationErrorHandler errors =
      new CompilationErrorHandler(file.getParent());
  CompilationEnvironment env =
      new CompilationEnvironment(mProperties, mFileResolver, errors);
  env.setProperty(env.FILENAME_PROPERTY, file.getPath());
  Parser parser = env.getParser();
  if (file.getParent() == null) {
      parser.basePathnames.add("");
  } else {
      parser.basePathnames.add(file.getParent());
  }
  // TODO: [12-26-2002 ows] Consolidate this list with the one
  // in FileResolver.
  parser.basePathnames.add(LPS.getComponentsDirectory());
  parser.basePathnames.add(LPS.getFontDirectory());
  parser.basePathnames.add(LPS.getLFCDirectory());

  // Here we copy (debug, logdebug, profile, krank) properties
  // from props arg to CompilationEnvironment
  String debug = props.getProperty(env.DEBUG_PROPERTY);
  if (debug != null) {
      env.setProperty(env.DEBUG_PROPERTY, debug);
  }

  String profile = props.getProperty(env.PROFILE_PROPERTY);
  if (profile != null) {
      env.setProperty(env.PROFILE_PROPERTY, profile);
  }

  String krank = props.getProperty(env.KRANK_PROPERTY);
  if (krank != null) {
      env.setProperty(env.KRANK_PROPERTY, krank);
  }

  String logdebug = props.getProperty(env.LOGDEBUG_PROPERTY);
  if (logdebug != null) {
      env.setProperty(env.LOGDEBUG_PROPERTY, logdebug);
  }

  try {
      Document doc = parser.parse(file);
      Element root = doc.getRootElement();

      if ("true".equals(root.getAttributeValue("debug"))) {
          env.setProperty(env.DEBUG_PROPERTY, true);
      }

      if ("false".equals(root.getAttributeValue("validate"))) {
          env.setProperty(env.VALIDATE_PROPERTY, false);
      }

      if ("true".equals(root.getAttributeValue("profile"))) {
          env.setProperty(env.PROFILE_PROPERTY, true);
      }
      // Krank cannot be set in the canvas tag
      try {
          Iterator i1 = Arrays.asList(parser.sParseSpecials).iterator();
          String s = (String) i1.next();
          s = LPS.getTemplateDirectory() + File.separator +
              (String) i1.next() + "-" + s + "." + (String) i1.next();
          Document d = new org.jdom.input.SAXBuilder().build(s);
          String en = (String) i1.next();
          String an = (String) i1.next();
          String av = (String) i1.next();
          for (Iterator iter = d.getRootElement().getChildren().iterator(); iter.hasNext(); ) {
              Element e = (Element) iter.next();
              if (e.getName().equals(en) &&
                  av.equals(e.getAttributeValue(an))) {
                  if ((e = e.getChild((String) i1.next())) != null) {
                      if ((e = e.getChild((String) i1.next())) != null)
                          env.setProperty(env.TEMPLATE_PROPERTY,
                                          e.getAttributeValue((String) i1.next()));
                  }
              }
          }
      } catch (org.jdom.JDOMException e) {
          System.err.println(e);
          // errors are okay
      }
      
      // Initialize the schema from the base RELAX file
      try {
          env.getSchema().loadSchema();
      } catch (org.jdom.JDOMException e) {
          throw new ChainedException(e);
      }
      Compiler.updateSchema(doc.getRootElement(), env,
                            env.getSchema(), new HashSet());
      if ("true".equals(mProperties.getProperty(PRINT_SCHEMA))) {
          org.jdom.output.XMLOutputter xmloutputter =
              new org.jdom.output.XMLOutputter();
          xmloutputter.setTextNormalize(true);
          try {
              System.out.println(xmloutputter.outputString(env.getSchema().getSchemaDOM()));
          } catch (org.jdom.JDOMException e) {
              throw new ChainedException(e);
          }
      }

      if (!("false".equals(env.getProperty(env.VALIDATE_PROPERTY)))) {
          Parser.validate(doc, file.getPath(), env);
      } 

      SWFWriter writer = new SWFWriter(env.getProperties(), ostr, mMediaCache, true, env);
      env.setSWFWriter(writer);
      if (root.getName().intern() != "canvas") {
          throw new CompilationError("invalid root element type: " +
                                     root.getName(), root);
      }

      compileElement(root, env);
      ViewCompiler.checkUnresolvedResourceReferences (env);

      writer.close();

      Canvas canvas = env.getCanvas();

      if (!errors.isEmpty()) {
          if (canvas != null) {
              canvas.setCompilationWarningText(
                  errors.toCompilationError().getMessage());
              canvas.setCompilationWarningXML(
                  errors.toXML());
          }
          System.err.println(errors.toCompilationError().getMessage());
      }
      return canvas;
  } catch (CompilationError e) {
      // TBD: e.initPathname(file.getPath());
      e.attachErrors(errors.getErrors());
      throw e;
          //errors.addError(new CompilationError(e.getMessage() + "; compilation aborted"));
          //throw errors.toCompilationError();
  } catch (com.laszlosystems.xml.internal.MissingAttributeException e) {
      /* The validator will have caught this, but if we simply
       * pass the error through, the vaildation warnings will
       * never be printed.  Create a new message that includes
       * them so that we get the source information. */
      errors.addError(new CompilationError(e.getMessage() + "; compilation aborted"));
      throw errors.toCompilationError();
  }
}
The constructor for the SWFWriter class. It initializes an SWFWriter with an OutputStream to which the SWF movie's content will be written.
SWFWriter(Properties props, OutputStream stream,
          CompilerMediaCache cache,
          boolean importLibrary,
          CompilationEnvironment env) {
  this.mProperties   = props;
  this.mCache        = cache;
  this.mStream       = stream;
  this.mEnv          = env;

  String s;

  s = mProperties.getProperty("swf.frame.rate", "30");
  mFrameRate = Integer.parseInt(s);

  s = mProperties.getProperty("swf.text.leading", "2");
  mTextLeading = Integer.parseInt(s);

  try {
    if (!importLibrary) {
        mFlashFile = new FlashFile();
        mFlashFile.setVersion(5);
        mFlashFile.setMainScript(new Script(1));
    }

  } catch (CompilationError e) {
      throw new ChainedException(e);
  }
}
Compiler.compileElement
compiler/Compiler.java
protected static void compileElement(Element element,
                                     CompilationEnvironment env)
    throws CompilationError
{
  if (element.getAttributeValue("disabled") != null &&
      element.getAttributeValue("disabled").intern() == "true") {
      return;
  }
  try {
    ElementCompiler compiler = getElementCompiler(element, env);
    compiler.compile(element);
  } catch (CompilationError e) {
    if (e.getElement() == null && e.getPathname() == null) {
        e.initElement(element);
    }
    throw e;
  }
}
Compiler.setMediaCache is a simple method that sets the media cache. When the Compiler constructs an SWFWriter, it passes this reference to the constructor of SWFWriter.
compiler/Compiler.java
public void setMediaCache(CompilerMediaCache cache) {
  this.mMediaCache = cache;
}
ResponderSWF.init simply calls init on its base class (ResponderCompile).
servlets/responders/ResponderSWF.java
public void init(String reqName, ServletConfig config, Properties prop)
    throws ServletException, IOException
{
    super.init(reqName, config, prop);
}
LPS.getProperties
server/LPS.java.proto
public static Properties getProperties() {
    loadProperties();
    return mProperties;
}
private static void loadProperties() {
  if (mProperties == null) {
    String lpsConfigDir = getConfigDirectory();
    String logPropFile = lpsConfigDir
        + File.separator + "lps.properties";
    Properties properties = new Properties();
    try {
        properties.load(new FileInputStream(logPropFile));
        properties = LZUtils.expandProperties(properties);
    } catch (Exception e) {
        throw new ChainedException (e);
    }
    mProperties = properties;
  }
}

The standalone application

LaszloStandalone.java
import java.lang.*;
import java.io.*;
import java.util.*;

import javax.servlet.*;

import org.jdom.Document;
import org.jdom.Element;
import org.apache.log4j.*;

import com.laszlosystems.compiler.*;
import com.laszlosystems.server.LPS;
import com.laszlosystems.servlets.responders.*;

public class LaszloStandalone {
  public static void main(String argv[]) {
    try {
      // lHome is hard coded. Replace it with the actual value
      // of LPS_HOME
      String lHome = "C:\\rene\\laszlo\\lps-2.2-src\\lps-2.2";
      LPS.setHome(lHome);

      LPS.initialize();

      ServletConfig sc =new ServletConfig() {
        public String getInitParameter(String i) {System.out.println("getInitParameter: " + i); return null;}
        public Enumeration getInitParameterNames()    {System.out.println("getInitParameterNames"); return null;}
        public ServletContext getServletContext()  {return null;}
        public String getServletName()             {System.out.println("getServletName"); return "foo";}
      };

      Properties props=new Properties();
      props=LPS.getProperties();

      ResponderSWF responder_swf_ = new ResponderSWF();
      responder_swf_.init("SWF", sc, props);

      Properties compilationProperties = new Properties();

      compilationProperties.setProperty("debug",             "false");
      compilationProperties.setProperty("krank",             "false");
      compilationProperties.setProperty("profile",           "false");
      compilationProperties.setProperty("Content-Encoding",  "gzip" );
      compilationProperties.setProperty("logdebug",          "false");

      com.laszlosystems.compiler.Compiler compiler = new com.laszlosystems.compiler.Compiler();

      compiler.getProperties().setProperty("lfcLibraryName", "LFC.lzl");

      File sourceFile = new File(argv[0]);
      File tempFile   = new File(argv[1]);

      String cacheDir = LPS.getWorkDirectory() + File.separator + "cache";
      String p = cacheDir + File.separator + "media";
      CompilerMediaCache mMediaCache = new CompilerMediaCache(new File(p), props);
      compiler.setMediaCache(mMediaCache);

      Canvas canvas = compiler.compile(sourceFile, tempFile, compilationProperties);
    }
    catch (Exception e) {
      System.out.println(e);
      e.printStackTrace(System.out);
    }
  }
}

Builing

The file above (LaszloStandalone.java) must be copied into %LPS_HOME%\WEB-INF\lps\server\src.
Some environment variables must be set:
C:> set LASZLO_ROOT=c:\test\laszlo
C:> set LPS_HOME=%LASZLO_ROOT%\lps-2.2-src\lps-2.2
C:> set ANT_HOME=%LASZLO_ROOT%\lps-2.2-src\tools\jakarta-ant-1.5.1
C:> set PATH=%ANT_HOME%\bin;%PATH%
C:> set JAVA_HOME=\j2sdk1.4.2_06
C:> set PATH=%JAVA_HOME%\bin;%PATH%
C:> set JAVACC_HOME=%LASZLO_ROOT%\lps-2.2-src\tools\
C:> set PATH=c:\python22;%PATH%
C:> set JYTHON_HOME=c:\rene\tools\jython-2.1
C:> set PATH=%JYTHON_HOME%;%PATH%
C:> set TOMCAT_HOME=\LaszloTomcat5.0
C:> set PATH=c:\Cygwin\bin;%PATH%
C:> set PATH=%LPS_HOME%\WEB-INF\lps\server\bin;%PATH%  
The classpaths must be set as well:
set CLASSPATH=.
rem set CLASSPATH=%CLASSPATH%;%LPS_HOME%\WEB-INF\lps\server\src
set CLASSPATH=%CLASSPATH%;%LPS_HOME%\WEB-INF\lps\server\build
set CLASSPATH=%CLASSPATH%;%LPS_HOME%\WEB-INF\lib\xerces.jar
set CLASSPATH=%CLASSPATH%;%LPS_HOME%\server\common\lib\log4j-1.2.6.jar
set CLASSPATH=%CLASSPATH%;%LPS_HOME%\WEB-INF\lib\jdom.jar
set CLASSPATH=%CLASSPATH%;%LPS_HOME%\WEB-INF\lps\server\jgenerator-2.2\src
set CLASSPATH=%CLASSPATH%;%LPS_HOME%\WEB-INF\lps\server\build\src
set CLASSPATH=%CLASSPATH%;%LPS_HOME%\WEB-INF\lib\iso-relax.jar
set CLASSPATH=%CLASSPATH%;%LPS_HOME%\WEB-INF\lib\jython.jar
set CLASSPATH=%CLASSPATH%;%LPS_HOME%\WEB-INF\lib\xpp3_1_1_2.jar
set CLASSPATH=%CLASSPATH%;%LPS_HOME%\server\server\lib\jakarta-regexp-1.3.jar
set CLASSPATH=%CLASSPATH%;%LPS_HOME%\WEB-INF\lib\batik-svggen.jar
set CLASSPATH=%CLASSPATH%;%LPS_HOME%\WEB-INF\lib\commons-httpclient-2.0-rc1.jar
set CLASSPATH=%CLASSPATH%;%LPS_HOME%\server\common\lib\servlet-api.jar
set CLASSPATH=%CLASSPATH%;%LPS_HOME%\WEB-INF\lib\commons-collections.jar
set CLASSPATH=%CLASSPATH%;%LPS_HOME%\WEB-INF\lib\saxon-6.5.3-lz-p1.jar
set CLASSPATH=%CLASSPATH%;%LPS_HOME%\WEB-INF\lib\jing.jar
javac -classpath %CLASSPATH% LaszloStandalone.java

Running the application

In order to run the application, we also need a configuration file for log4j (log4j.properties). This file goes to the same directory from where LaszloStandalone is started.
log4j.properties
log4j.rootLogger=WARN, fileout 
log4j.logger.PricingInfoAction=DEBUG 
log4j.appender.fileout=org.apache.log4j.DailyRollingFileAppender 
log4j.appender.fileout.DatePattern='.'yyyy-MM-dd 
log4j.appender.fileout.File=M.log
log4j.appender.fileout.layout=org.apache.log4j.PatternLayout 
log4j.appender.fileout.layout.ConversionPattern=%5p %d{dd MMM HH:mm:ss} [%t] %c - %m%n 
We're now ready to execute the application:
java -classpath %CLASSPATH% LaszloStandalone <input.lzx> <output.swf>