Package org.apache.cocoon.components.flow

Source Code of org.apache.cocoon.components.flow.AbstractInterpreter

package org.apache.cocoon.components.flow;

import java.lang.System;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import org.apache.avalon.framework.component.Component;
import org.apache.avalon.framework.component.ComponentException;
import org.apache.avalon.framework.component.ComponentManager;
import org.apache.avalon.framework.component.Composable;
import org.apache.avalon.framework.context.ContextException;
import org.apache.avalon.framework.context.Contextualizable;
import org.apache.avalon.framework.logger.AbstractLoggable;
import org.apache.avalon.framework.thread.ThreadSafe;
import org.apache.cocoon.Constants;
import org.apache.cocoon.components.source.SourceFactory;
import org.apache.cocoon.components.treeprocessor.CategoryNode;
import org.apache.cocoon.components.treeprocessor.InvokeContext;
import org.apache.cocoon.components.treeprocessor.MapStackResolver;
import org.apache.cocoon.components.treeprocessor.ProcessingNode;
import org.apache.cocoon.components.treeprocessor.sitemap.PipelinesNode;
import org.apache.cocoon.environment.Context;
import org.apache.cocoon.environment.Environment;

/**
* Abstract superclass for various scripting languages used by Cocoon
* for flow control. Defines some useful behavior like the ability to
* reload script files if they get modified (useful when doing
* development), and passing the control to Cocoon's sitemap for
* result page generation.
*
* @author <a href="mailto:ovidiu@cup.hp.com">Ovidiu Predescu</a>
* @since March 15, 2002
*/
public abstract class AbstractInterpreter extends AbstractLoggable
  implements Component, Composable, Contextualizable, Interpreter, ThreadSafe
{
  /**
   * Hash table of source locations -> ScriptSource instances
   */
  protected HashMap scripts = new HashMap();

  /**
   * List of source locations that need to be resolved.
   */
  protected ArrayList needResolve = new ArrayList();

  /**
   * When was the last time we checked for script modifications. Used
   * only if {@link reloadScripts} is true.
   */
  protected long lastTimeCheck = 0;

  protected org.apache.cocoon.environment.Context context;
  protected ComponentManager manager;
  protected ContinuationsManager continuationsMgr;

  /**
   * Whether reloading of scripts should be done. Specified through
   * the "reload-scripts" attribute in <code>flow.xmap</code>.
   */
  protected boolean reloadScripts;

  /**
   * Interval between two checks for modified script files. Specified
   * through the "check-time" XML attribute in <code>flow.xmap</code>.
   */
  protected long checkTime;

  protected CategoryNode resources;

  public void compose(ComponentManager manager)
    throws ComponentException
  {
    this.manager = manager;
//     System.out.println("AbstractInterpreter: ComponentManager = " + manager);
    // FIXME: Why is the manager null here?
    if (manager != null)
      continuationsMgr
        = (ContinuationsManager)manager.lookup(ContinuationsManager.ROLE);
  }

  public void contextualize(org.apache.avalon.framework.context.Context context)
    throws ContextException
  {
    this.context = (Context)context.get(Constants.CONTEXT_ENVIRONMENT_CONTEXT);
  }

  public void setReloadScripts(boolean yn)
  {
    reloadScripts = yn;
  }

  public void setCheckTime(long time)
  {
    checkTime = time;
  }

  public void setResources(CategoryNode resources)
  {
    this.resources = resources;
  }

  /**
   * Registers a source file with the interpreter. Using this method
   * an implementation keeps track of all the script files which are
   * compiled. This allows them to reload the script files which get
   * modified on the file system.
   *
   * <p>The parsing/compilation of a script file by an interpreter
   * happens in two phases. In the first phase the file's location is
   * registered in the <code>needResolve</code> array.
   *
   * <p>The second is possible only when a Cocoon
   * <code>Environment</code> is passed to the Interpreter. This
   * allows the file location to be resolved using Cocoon's
   * <code>SourceFactory</code> class.
   *
   * <p>Once a file's location can be resolved, it is removed from the
   * <code>needResolve</code> array and placed in the
   * <code>scripts</code> hash table. The key in this hash table is
   * the file location string, and the value is a
   * DelayedRefreshSourceWrapper instance which keeps track of when
   * the file needs to re-read.
   *
   * @param source the location of the script
   *
   * @see org.apache.cocoon.components.source.SourceFactory
   * @see org.apache.cocoon.environment.Environment
   * @see org.apache.cocoon.components.source.DelayedRefreshSourceWrapper
   */
  public void register(String source)
    throws Exception
  {
    synchronized(this) {
      needResolve.add(source);
    }
  }

  /**
   * Unregister the source file. Called from <code>ScriptNode</code>
   * when a tree corresponding to a sitemap is decommissioned.
   *
   * @param source a <code>String</code> value
   */
  public void unregister(String source)
  {
    synchronized(this) {
      scripts.remove(source);
      int index = needResolve.indexOf(source);
      if (index != -1)
        needResolve.remove(index);
    }
  }

  /**
   * Reloads any modified script files.
   *
   * <p>It checks to see if any of the files already read in (those
   * present in the <code>scripts</code> hash map) have been
   * modified.
   *
   * <p>It also checks to see if any script files have been registered
   * with the interpreter since the last call to
   * <code>checkForModifiedScripts</code>. These files are stored in
   * the temporary array <code>needResolve</code>. If any such files
   * are found, they are read in.
   *
   * @param environment an <code>Environment</code> value
   */
  public void checkForModifiedScripts(Environment environment)
    throws Exception
  {
    if (reloadScripts
        && System.currentTimeMillis() >= lastTimeCheck + checkTime) {
      // FIXME: should we worry about synchronization?
      Iterator iter = scripts.values().iterator();
      while (iter.hasNext()) {
        ScriptSource src = (ScriptSource)iter.next();
        if (src.getLastModified() > lastTimeCheck) {
          try {
            src.refresh(environment);
          }
          catch (Exception ex) {
            System.out.println("Error reading script " + src.getSourceName()
                               + ", ignoring!");
          }
        }
      }
    }

    // FIXME: remove the need for synchronization
    synchronized (this) {
      int size = needResolve.size();
      for (int i = 0; i < size; i++) {
        String source = (String)needResolve.get(0);
        ScriptSource src = new ScriptSource(this, source);
        scripts.put(source, src);
        needResolve.remove(0);
        try {
          src.refresh(environment);
        }
        catch (Exception ex) {
          System.out.println("Error reading script " + source + ", ignoring!");
        }
      }
    }

    // Update the time of the last check. If an exception occurs, this
    // is not executed, so the next request will force a reparse of
    // the script files because of an old time stamp.
    lastTimeCheck = System.currentTimeMillis();
  }

  public void processPipeline(String name, Map pipelineArgs, Object bizData,
                              WebContinuation continuation,
                              Environment environment, InvokeContext ctx)
    throws Exception
  {
    if (ctx == null) {
      String msg = "Cannot invoke pipeline with a null InvokeContext! Make sure"
        + " you're calling the pipeline during the execution of a request.";
      throw new RuntimeException(msg);
    }

    environment.setAttribute("bean-dict", bizData);
    environment.setAttribute("kont", continuation);

    ProcessingNode pipeline
      = resources.getNodeByName(MapStackResolver.unescape(name));

    if (pipelineArgs != null)
      ctx.pushMap(pipelineArgs);
    try {
      pipeline.invoke(environment, ctx);
    }
    finally {
      environment.removeAttribute("bean-dict");
      environment.removeAttribute("kont");
      if (pipelineArgs != null)
        ctx.popMap();
    }
  }

  public void forwardTo(String uri, Object bizData,
                        WebContinuation continuation,
                        Environment environment, InvokeContext ctx)
    throws Exception
  {
    if (ctx == null) {
      String msg = "Cannot invoke pipeline with a null InvokeContext! Make sure"
        + " you're calling the pipeline during the execution of a request.";
      throw new RuntimeException(msg);
    }

    environment.setAttribute("bean-dict", bizData);
    environment.setAttribute("kont", continuation);

    try {
      PipelinesNode.getRedirector(environment).redirect(false, uri);
    }
    finally {
      environment.removeAttribute("bean-dict");
      environment.removeAttribute("kont");
    }
  }
}
TOP

Related Classes of org.apache.cocoon.components.flow.AbstractInterpreter

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.