Package org.huihoo.willow.core

Source Code of org.huihoo.willow.core.StandardEngine$EngineBackgroundProcessor

//----------------------------BEGIN LICENSE----------------------------
/*
* Willow : the Open Source WorkFlow Project
* Distributable under GNU LGPL license by gun.org
*
* Copyright (C) 2004-2010 huihoo.org
* Copyright (C) 2004-2010  ZosaTapo <dertyang@hotmail.com>
*
* ====================================================================
* Project Homepage : http://www.huihoo.org/willow
* Source Forge     : http://sourceforge.net/projects/huihoo
* Mailing list     : willow@lists.sourceforge.net
*/
//----------------------------END  LICENSE-----------------------------
package org.huihoo.willow.core;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.Method;
import java.net.URL;
import java.util.HashMap;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.huihoo.willow.Context;
import org.huihoo.willow.Engine;
import org.huihoo.willow.EngineDeployer;
import org.huihoo.willow.Globals;
import org.huihoo.willow.Lifecycle;
import org.huihoo.willow.LifecycleException;
import org.huihoo.willow.Service;
import org.huihoo.willow.session.SessionManager;
import org.huihoo.willow.store.UserDatabaseRealm;
import org.huihoo.willow.util.ServerInfo;
import org.huihoo.workflow.store.RealmDatabase;

/**
* @author reic
*
* To change the template for this generated type comment go to
* Window - Preferences - Java - Code Generation - Code and Comments
*/
public class StandardEngine extends ContainerBase implements EngineDeployer, Engine
{

  private static Log log = LogFactory.getLog(StandardEngine.class);

  // ----------------------------------------------------------- Constructors

  /**
   * Create a new StandardEngine component with the default basic Valve.
   */
  public StandardEngine()
  {

    super();

    // By default, the engine will hold the reloading thread
    backgroundProcessorDelay = 10;

  }

  // ----------------------------------------------------- Instance Variables
  /**
   * The child Context belonging to this , keyed by name.
   */
  protected HashMap children = new HashMap();
 
  /**
   * The descriptive information string for this implementation.
   */
  private static final String info = "org.huihoo.willow.core.StandardEngine/1.0";

  /**
   * The <code>Service</code> that owns this Engine, if any.
   */
  private Service service = null;

  /**
    * The application root for this Engine.
    */
  private String engineBase = ".";

  /**
    * The auto deploy flag for this Engine.
    */
  private boolean autoDeploy = true;

  /**
   * The deploy on startup flag for this Engine.
   */
  private boolean deployOnStartup = true;

  /**
   * The Java class name of the default context configuration class
   * for deployed web applications.
   */
  private String configClass = "org.huihoo.willow.startup.ContextConfig";

  /**
   * The Java class name of the default ParameterContext implementation class for
   * deployed web applications.
   */
  private String contextClass = "org.huihoo.willow.core.StandardContext";

  /**
   * The <code>EngineDeployer</code> to whom we delegate application
   * deployment requests.
   */
  private EngineDeployer deployer = null;

  /**
   * The session timeout (in minutes) for this web application.
   */
  private int sessionTimeout = 30;

  /**
   * Frequency of the session expiration, and related manager operations.
   * SessionManager operations will be done once for the specified amount of
   * backgrondProcess calls (ie, the lower the amount, the most often the
   * checks will occur).
   */
  private int managerChecksFrequency = 6;

  /**
   * Iteration count for background processing.
   */
  private int count = 0;

  /**
   * Work Directory base for applications.
   */
  private String workDir = null;

  /**
   * The Realm with which this Container is associated.
   */
  private RealmDatabase realmDatabase = null;

  /**
   * The SessionManager implementation with which this Engine is associated.
   */
  protected SessionManager manager = null;

  // ------------------------------------------------------------- Properties
  public RealmDatabase getRealmDatabase()
  {
    return this.realmDatabase;
  }

  public void setRealmDatabase(RealmDatabase realmDatabase)
  {
    //  Change components if necessary
    RealmDatabase oldRealm = this.realmDatabase;
    if (oldRealm == realmDatabase)
      return;
    this.realmDatabase = realmDatabase;

    // Stop the old component if necessary
    if (started && (oldRealm != null) && (oldRealm instanceof Lifecycle))
    {
      try
      {
        ((Lifecycle) oldRealm).stop();
      }
      catch (LifecycleException e)
      {
        log.error("StandardEngine.setRealmDatabase: stop: ", e);
      }
    }

    // Start the new component if necessary
    if ((realmDatabase != null) && (realmDatabase instanceof UserDatabaseRealm))
    {
      ((UserDatabaseRealm) realmDatabase).setEngine(this);
    }

    if (started && (realmDatabase != null) && (realmDatabase instanceof Lifecycle))
    {
      try
      {
        ((Lifecycle) realmDatabase).start();
      }
      catch (LifecycleException e)
      {
        log.error("StandardEngine.setRealmDatabase: start: ", e);
      }
    }

    support.firePropertyChange("realmDatabase", oldRealm, this.realmDatabase);
  }

  /**
   * Return the application root for this Engine.  This can be an absolute
   * pathname, a relative pathname
   */
  public String getEngineBase()
  {
    return (this.engineBase);
  }

  /**
   * Return the application root for this Engine.
   */
  public File getAbsoluteEngineBase()
  {
    String absolute_engineBase = getEngineBase();

    File absolute_engineBaseFile = new File(absolute_engineBase);

    if (!absolute_engineBaseFile.isAbsolute())
    {
      absolute_engineBaseFile =
        new File(System.getProperty(Globals.PROPS_WILLOW_HOME), absolute_engineBase);
    }
    return absolute_engineBaseFile;
  }

  /**
   * Set the application root for this Engine.  This can be an absolute
   * pathname, a relative pathname
   *
   * @param appBase The new application root
   */
  public void setEngineBase(String engineBase)
  {

    String oldEngineBase = this.engineBase;
    this.engineBase = engineBase;
    support.firePropertyChange("engineBase", oldEngineBase, this.engineBase);

  }

  /**
   * Return the value of the auto deploy flag.  If true, it indicates that
   * this Engine's child webapps will be dynamically deployed.
   */
  public boolean getAutoDeploy()
  {

    return (this.autoDeploy);

  }

  /**
   * Set the auto deploy flag value for this Engine.
   *
   * @param autoDeploy The new auto deploy flag
   */
  public void setAutoDeploy(boolean autoDeploy)
  {

    boolean oldAutoDeploy = this.autoDeploy;
    this.autoDeploy = autoDeploy;
    support.firePropertyChange("autoDeploy", oldAutoDeploy, this.autoDeploy);

  }

  /**
   * Return the Java class name of the context configuration class
   * for new web applications.
   */
  public String getConfigClass()
  {

    return (this.configClass);

  }

  /**
   * Set the Java class name of the context configuration class
   * for new web applications.
   *
   * @param configClass The new context configuration class
   */
  public void setConfigClass(String configClass)
  {

    String oldConfigClass = this.configClass;
    this.configClass = configClass;
    support.firePropertyChange("configClass", oldConfigClass, this.configClass);

  }

  /**
   * Return the Java class name of the ParameterContext implementation class
   * for new web applications.
   */
  public String getContextClass()
  {

    return (this.contextClass);

  }

  /**
   * Set the Java class name of the ParameterContext implementation class
   * for new web applications.
   *
   * @param contextClass The new context implementation class
   */
  public void setContextClass(String contextClass)
  {

    String oldContextClass = this.contextClass;
    this.contextClass = contextClass;
    support.firePropertyChange("contextClass", oldContextClass, this.contextClass);

  }

  /**
   * Return the default session timeout (in minutes) for this
   * org.huihoo.workflow client
   */
  public int getSessionTimeout()
  {

    return (this.sessionTimeout);

  }

  /**
   * Set the default session timeout (in minutes) for this
   * org.huihoo.workflow client
   *
   * @param timeout The new default session timeout
   */
  public void setSessionTimeout(int timeout)
  {

    int oldSessionTimeout = this.sessionTimeout;

    this.sessionTimeout = (timeout == 0) ? -1 : timeout;
    support.firePropertyChange(
      "sessionTimeout",
      new Integer(oldSessionTimeout),
      new Integer(this.sessionTimeout));

  }

  /**
   * Return the <code>Service</code> with which we are associated (if any).
   */
  public Service getService()
  {

    return (this.service);

  }

  /**
   * Set the <code>Service</code> with which we are associated (if any).
   *
   * @param service The service that owns this Engine
   */
  public void setService(Service service)
  {
    this.service = service;
  }


  /**
   * Return the child Context, associated with this , with
   * the specified name (if any); otherwise, return <code>null</code>
   *
   * @param name Name of the child Context to be retrieved
   */
  public Context findChild(String name)
  {

    if (name == null)
      return (null);
    synchronized (children)
    { // Required by post-start changes
      return ((Context) children.get(name));
    }

  }

  /**
   * Return the set of children Contexts associated with this .
   * If this  has no children, a zero-length array is returned.
   */
  public Context[] findChildren()
  {

    synchronized (children)
    {
      Context results[] = new Context[children.size()];
      return ((Context[]) children.values().toArray(results));
    }

  }

  /**
   * Remove an existing child Context from association with this
   *
   * @param child Existing child Context to be removed
   */
  public void removeChild(Context child)
  {

    synchronized (children)
    {
      if (children.get(child.getName()) == null)
        return;
      children.remove(child.getName());
    }

    if (started && (child instanceof Lifecycle))
    {
      try
      {
        if (child instanceof ContainerBase)
        {
          if (((ContainerBase) child).started)
          {
            ((Lifecycle) child).stop();
          }
        }
        else
        {
          ((Lifecycle) child).stop();
        }
      }
      catch (LifecycleException e)
      {
        log.error("ContainerBase.removeChild: stop: ", e);
      }
    }
  }
  /**
   * Return the value of the deploy on startup flag.  If true, it indicates
   * that this Engine's child webapps should be discovred and automatically
   * deployed at startup time.
   */
  public boolean getDeployOnStartup()
  {

    return (this.deployOnStartup);

  }

  /**
   * Set the deploy on startup flag value for this Engine.
   *
   * @param autoDeploy The new deploy on startup flag
   */
  public void setDeployOnStartup(boolean deployOnStartup)
  {

    boolean oldDeployOnStartup = this.deployOnStartup;
    this.deployOnStartup = deployOnStartup;
    support.firePropertyChange("deployOnStartup", oldDeployOnStartup, this.deployOnStartup);

  }

  /**
   * Return the SessionManager with which this Engine is associated.
   */
  public SessionManager getSessionManager()
  {
    return (manager);
  }

  /**
   * Set the SessionManager with which this Engine is associated.
   *
   * @param manager The newly associated SessionManager
   */
  public synchronized void setSessionManager(SessionManager manager)
  {

    // Change components if necessary
    SessionManager oldManager = this.manager;
    if (oldManager == manager)
    {
      return;
    }
    this.manager = manager;

    // Stop the old component if necessary
    if (started && (oldManager != null) && (oldManager instanceof Lifecycle))
    {
      try
      {
        ((Lifecycle) oldManager).stop();
      }
      catch (LifecycleException e)
      {
        log.error("StandardEngine.setSessionManager: stop: ", e);
      }
    }

    // Start the new component if necessary
    if (manager != null)
      manager.setEngine(this);
    if (started && (manager != null) && (manager instanceof Lifecycle))
    {
      try
      {
        ((Lifecycle) manager).start();
      }
      catch (LifecycleException e)
      {
        log.error("StandardEngine.setSessionManager: start: ", e);
      }
    }

    // Report this property change to interested listeners
    support.firePropertyChange("sessionManager", oldManager, this.manager);

  }

  /**
   * Return the canonical, fully qualified, name of the engine
   * this Container represents.
   */
  public String getName()
  {

    return (name);

  }
 
 

  /**
   * Set the canonical, fully qualified, name of the virtual Engine
   * this Container represents.
   *
   * @param name Virtual Engine name
   *
   * @exception IllegalArgumentException if name is null
   */
  public void setName(String name)
  {

    if (name == null)
    {
      throw new IllegalArgumentException(sm.getString("standardEngine.nullName"));
    }

    name = name.toLowerCase(); // Internally all names are lower case

    String oldName = this.name;
    this.name = name;
    support.firePropertyChange("name", oldName, this.name);

  }
 
  /**
   * Engine work directory base.
   */
  public String getWorkDir()
  {
    if (workDir != null)
    {
      return workDir;
    }

    workDir = org.huihoo.willow.startup.Constants.WORK_DIRECTORY;

    return (workDir);
  }

  public File getAbsoluteWorkDir()
  {
    String absolute_workDir = getWorkDir();
    File absolute_workDirFile = new File(absolute_workDir);

    if (!absolute_workDirFile.isAbsolute())
    {
      absolute_workDirFile =
        new File(System.getProperty(Globals.PROPS_WILLOW_HOME), absolute_workDir);
    }
    return absolute_workDirFile;
  }

  /**
   * Engine work directory base.
   */
  public void setWorkDir(String workDir)
  {

    this.workDir = workDir;
  }

  // --------------------------------------------------------- Public Methods
  /**
   * Add a child Context
   *
   * @param child Child context to be added
   */
  public void addChild(Context child)
  {
    log.debug("Add child " + child + " " + this);
   
    synchronized (children)
    {
      if (children.get(child.getName()) != null)
      {
        throw new IllegalArgumentException(
          "addChild:  Child name '" + child.getName() + "' is not unique");
      }
     
      child.setEngine(this);
     
      if (started && (child instanceof Lifecycle))
      {
        try
        {
          ((Lifecycle) child).start();
        }
        catch (LifecycleException e)
        {
          log.error("standardEngine.addChild: start: ", e);
          throw new IllegalStateException("standardEngine.addChild: start: " + e);
        }
      }
      children.put(child.getName(), child);
    }

  }

  /**
   * Return descriptive information about this Container implementation and
   * the corresponding version number, in the format
   * <code>&lt;description&gt;/&lt;version&gt;</code>.
   */
  public String getInfo()
  {

    return (info);

  }

  /**
   * Start this Engine component.
   *
   * @exception LifecycleException if a startup error occurs
   */
  public void start() throws LifecycleException
  {
    if (started)
    {
      return;
    }

    // Log our server identification information
    log.info("Starting WorkflowService Engine: " + ServerInfo.getServerInfo());

    if ((realmDatabase != null) && (realmDatabase instanceof Lifecycle))
    {
      try
      {
        ((Lifecycle) realmDatabase).start();
      }
      catch (LifecycleException e)
      {
        log.error("StandardEngine.setRealmDatabase: start: ", e);
      }
    }

    if (manager == null)
    {
      manager = new SessionManager();
      manager.setEngine(this);
    }

    if ((manager != null) && (manager instanceof Lifecycle))
    {
      try
      {
        ((Lifecycle) manager).start();
      }
      catch (LifecycleException e)
      {
        log.error("StandardEngine.setSessionManager: start: ", e);
      }
    }
   
    // Start our child containers, if any
    Context children[] = findChildren();
    for (int i = 0; i < children.length; i++)
    {     
      if (children[i] instanceof Lifecycle)
      {
        ((Lifecycle) children[i]).start();
      }
    }
   
    // Standard container startup
    super.start();

  }

  public void stop() throws LifecycleException
  {
    // Stop our child containers, if any
    Context children[] = findChildren();
    for (int i = 0; i < children.length; i++)
    {
      if (children[i] instanceof Lifecycle)
      {
        ((Lifecycle) children[i]).stop();
      }
    }
   
    if ((realmDatabase != null) && (realmDatabase instanceof Lifecycle))
    {
      try
      {
        ((Lifecycle) realmDatabase).stop();
      }
      catch (LifecycleException e)
      {
        log.error("StandardEngine.setRealmDatabase: stop: ", e);
      }
    }

    if ((manager != null) && (manager instanceof Lifecycle))
    {
      try
      {
        ((Lifecycle) manager).stop();
      }
      catch (LifecycleException e)
      {
        log.error("StandardEngine.setSessionManager: stop: ", e);
      }
    }
    super.stop();
  }

  /**
   * Return a String representation of this component.
   */
  public String toString()
  {

    StringBuffer sb = new StringBuffer("StandardEngine[");
    sb.append(getName());
    sb.append("]");
    return (sb.toString());

  }

  // ------------------------------------------------------- EngineDeployer Methods

  /**
   * Install a new web application, whose web application archive is at the
   * specified URL, into this container with the specified context path.
   * A context path of "" (the empty string) should be used for the root
   * application for this container.  Otherwise, the context path must
   * start with a slash.
   * <p>
   * If this application is successfully installed, a ContainerEvent of type
   * <code>INSTALL_EVENT</code> will be sent to all registered listeners,
   * with the newly created <code>ParameterContext</code> as an argument.
   *
   * @param contextName The context path to which this application should
   *  be installed (must be unique)
   * @param war A URL of type "jar:" that points to a WAR file, or type
   *  "file:" that points to an unpacked directory structure containing
   *  the web application to be installed
   *
   * @exception IllegalArgumentException if the specified context path
   *  is malformed (it must be "" or start with a slash)
   * @exception IllegalStateException if the specified context path
   *  is already attached to an existing web application
   * @exception IOException if an input/output error was encountered
   *  during installation
   */
  public void install(String contextName, URL war) throws IOException
  {
    getDeployer().install(contextName, war);
  }

  /**
   * Return the Context for the deployed application that is associated
   * with the specified context path (if any); otherwise return
   * <code>null</code>.
   *
   * @param contextName The context path of the requested web application
   */
  public Context findDeployedApp(String contextName)
  {

    return (getDeployer().findDeployedApp(contextName));

  }

  /**
   * Return the context paths of all deployed web applications in this
   * Container.  If there are no deployed applications, a zero-length
   * array is returned.
   */
  public String[] findDeployedApps()
  {

    return (getDeployer().findDeployedApps());

  }

  /**
   * Remove an existing web application, attached to the specified context
   * path.  If this application is successfully removed, a
   * ContainerEvent of type <code>REMOVE_EVENT</code> will be sent to all
   * registered listeners, with the removed <code>Context</code> as
   * an argument.
   *
   * @param contextName The context path of the application to be removed
   *
   * @exception IllegalArgumentException if the specified context path
   *  is malformed (it must be "" or start with a slash)
   * @exception IllegalArgumentException if the specified context path does
   *  not identify a currently installed web application
   * @exception IOException if an input/output error occurs during
   *  removal
   */
  public void remove(String contextName) throws IOException
  {

    getDeployer().remove(contextName);

  }

  /**
   * Remove an existing web application, attached to the specified context
   * path.  If this application is successfully removed, a
   * ContainerEvent of type <code>REMOVE_EVENT</code> will be sent to all
   * registered listeners, with the removed <code>Context</code> as
   * an argument. Deletes the web application war file and/or directory
   * if they exist in the Engine's appBase.
   *
   * @param contextName The context path of the application to be removed
   * @param undeploy boolean flag to remove web application from server
   *
   * @exception IllegalArgumentException if the specified context path
   *  is malformed (it must be "" or start with a slash)
   * @exception IllegalArgumentException if the specified context path does
   *  not identify a currently installed web application
   * @exception IOException if an input/output error occurs during
   *  removal
   */
  public void remove(String contextName, boolean undeploy) throws IOException
  {

    getDeployer().remove(contextName, undeploy);

  }

  /**
   * Start an existing web application, attached to the specified context
   * path.  Only starts a web application if it is not running.
   *
   * @param contextName The context path of the application to be started
   *
   * @exception IllegalArgumentException if the specified context path
   *  is malformed (it must be "" or start with a slash)
   * @exception IllegalArgumentException if the specified context path does
   *  not identify a currently installed web application
   * @exception IOException if an input/output error occurs during
   *  startup
   */
  public void start(String contextName) throws IOException
  {

    getDeployer().start(contextName);

  }

  /**
   * Stop an existing web application, attached to the specified context
   * path.  Only stops a web application if it is running.
   *
   * @param contextName The context path of the application to be stopped
   *
   * @exception IllegalArgumentException if the specified context path
   *  is malformed (it must be "" or start with a slash)
   * @exception IllegalArgumentException if the specified context path does
   *  not identify a currently installed web application
   * @exception IOException if an input/output error occurs while stopping
   *  the web application
   */
  public void stop(String contextName) throws IOException
  {

    getDeployer().stop(contextName);

  }

  /**
   * Execute a periodic task, such as reloading, etc. This method will be
   * invoked inside the classloading context of this container. Unexpected
   * throwables will be caught and logged.
   */
  public void backgroundProcess()
  {
    lifecycle.fireLifecycleEvent("check", null);

    count = (count + 1) % managerChecksFrequency;

    if ((getSessionManager() != null) && (count == 0))
    {
      getSessionManager().processExpires();
    }
  }
  // ------------------------------------------------------ Protected Methods

  static String STANDARD_ENGINE_DEPLOYER = "org.huihoo.willow.core.StandardEngineDeployer";

  public EngineDeployer getDeployer()
  {
    if (deployer != null)
    {
      return deployer;
    }

    log.info("Create Engine deployer for direct deployment ");

    try
    {
      Class c = Class.forName(STANDARD_ENGINE_DEPLOYER);
      deployer = (EngineDeployer) c.newInstance();
      Method m = c.getMethod("setEngine", new Class[] { Engine.class });
      m.invoke(deployer, new Object[] { this });
    }
    catch (Throwable t)
    {
      log.error("Error creating deployer ", t);
    }
    return deployer;
  }

  public void setDeployer(EngineDeployer d)
  {
    this.deployer = d;
  }
 
  /**
   * Start the background thread that will periodically check for
   * session timeouts.
   */
  protected void threadStart()
  {
    if (thread != null)
      return;
   
    if (backgroundProcessorDelay <= 0)
      return;

    threadDone = false;
    String threadName = "EngineBackgroundProcessor[" + toString() + "]";
    thread = new Thread(new EngineBackgroundProcessor(), threadName);
    thread.setDaemon(true);
    thread.start();
  }

  /**
   * Stop the background thread that is periodically checking for
   * session timeouts.
   */
  protected void threadStop()
  {
    if (thread == null)
      return;

    threadDone = true;
    thread.interrupt();
    thread = null;
  }

  // -------------------------------------- EngineExecuteDelay Inner Class

  /**
   * Private thread class to invoke the backgroundProcess method
   * of this container and its children after a fixed delay.
   */
  protected class EngineBackgroundProcessor implements Runnable
  {
    public void run()
    {
      while (!threadDone)
      {
        try
        {
          Thread.sleep(backgroundProcessorDelay * 1000L);
        }
        catch (InterruptedException e)
        {
          ;
        }
        if (!threadDone)
        {
          Engine engine=StandardEngine.this;
          ClassLoader cl = Thread.currentThread().getContextClassLoader();
         
          try
          {   
            backgroundProcess();
          }
          catch (Throwable t)
          {
            log.error("Exception invoking periodic operation: ", t);
          }
          finally
          {
            Thread.currentThread().setContextClassLoader(cl);
          }
                       
          Context[] children = engine.findChildren();
          for (int i = 0; i < children.length; i++)
          {
            if (children[i].getBackgroundProcessorDelay() <= 0)
            {
              try
              {
                if (children[i].getLoader() != null)
                {
                  Thread.currentThread().setContextClassLoader(children[i].getLoader().getClassLoader());
                }
                children[i].backgroundProcess();
              }
              catch (Throwable t)
              {
                log.error("Exception invoking periodic operation: ", t);
              }
              finally
              {
                Thread.currentThread().setContextClassLoader(cl);
              }
            }
          }
         
        }
      }
     
    }
  }
}
TOP

Related Classes of org.huihoo.willow.core.StandardEngine$EngineBackgroundProcessor

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.