Package railo.runtime.tag

Source Code of railo.runtime.tag.Lock

package railo.runtime.tag;

import railo.runtime.PageContext;
import railo.runtime.PageContextImpl;
import railo.runtime.config.ConfigWebImpl;
import railo.runtime.debug.ActiveLock;
import railo.runtime.exp.ApplicationException;
import railo.runtime.exp.LockException;
import railo.runtime.exp.PageException;
import railo.runtime.ext.tag.BodyTagTryCatchFinallyImpl;
import railo.runtime.lock.LockData;
import railo.runtime.lock.LockManager;
import railo.runtime.lock.LockManagerImpl;
import railo.runtime.lock.LockTimeoutException;
import railo.runtime.lock.LockTimeoutExceptionImpl;
import railo.runtime.op.Caster;
import railo.runtime.type.Struct;
import railo.runtime.type.StructImpl;
import railo.runtime.type.dt.TimeSpan;
import railo.runtime.type.scope.ApplicationImpl;
import railo.runtime.type.scope.RequestImpl;
import railo.runtime.type.scope.ServerImpl;

/**
* Provides two types of locks to ensure the integrity of shared data: Exclusive lock and Read-only
*   lock. An exclusive lock single-threads access to the CFML constructs in its body. Single-threaded access
*   implies that the body of the tag can be executed by at most one request at a time. A request executing
*   inside a cflock tag has an "exclusive lock" on the tag. No other requests can start executing inside the
*   tag while a request has an exclusive lock. CFML issues exclusive locks on a first-come, first-served
*   basis. A read-only lock allows multiple requests to access the CFML constructs inside its body concurrently.
*   Therefore, read-only locks should be used only when the shared data is read only and not modified. If another
*   request already has an exclusive lock on the shared data, the request waits for the exclusive lock to be
*   released.
*
*
*
**/
public final class Lock extends BodyTagTryCatchFinallyImpl {



  private static final short SCOPE_NONE=0;
  private static final short SCOPE_SERVER=1;
  private static final short SCOPE_APPLICATION=2;
  private static final short SCOPE_SESSION=3;
  private static final short SCOPE_REQUEST=4;
 
  private String id="anonymous";
 
  /** Specifies the maximum amount of time, in seconds, to wait to obtain a lock. If a lock can be
  **     obtained within the specified period, execution continues inside the body of the tag. Otherwise, the
  **     behavior depends on the value of the throwOnTimeout attribute. */
  private int timeoutInMillis;
 
  /** readOnly or Exclusive. Specifies the type of lock: read-only or exclusive. Default is Exclusive.
  **   A read-only lock allows more than one request to read shared data. An exclusive lock allows only one
  **   request to read or write to shared data. */
  private short type=LockManager.TYPE_EXCLUSIVE;
 
  /** Specifies the scope as one of the following: Application, Server, or Session. This attribute is mutually
  **   exclusive with the name attribute. */
  private short scope=SCOPE_NONE;
 
  /** Yes or No. Specifies how timeout conditions are handled. If the value is Yes, an exception is
  **   generated to provide notification of the timeout. If the value is No, execution continues past the
  **    cfclock tag. Default is Yes. */
  private boolean throwontimeout = true;
 
  /** Specifies the name of the lock.  */
  private String name;
 
  private LockManager manager;
    private LockData data=null;
  private long start;

  @Override
  public void release() {
    super.release();
    type = LockManager.TYPE_EXCLUSIVE;
    scope = SCOPE_NONE;
    throwontimeout = true;
    name = null;
        manager=null;
        this.data=null;
        id="anonymous";
        timeoutInMillis=0;
  }


  /**
   * @param id the id to set
   */
  public void setId(String id) {
    this.id = id;
  }
 
  /** set the value timeout
  *  Specifies the maximum amount of time, in seconds, to wait to obtain a lock. If a lock can be
  *     obtained within the specified period, execution continues inside the body of the tag. Otherwise, the
  *     behavior depends on the value of the throwOnTimeout attribute.
  * @param timeout value to set
  **/
  public void setTimeout(Object oTimeout) throws PageException {
    if(oTimeout instanceof TimeSpan)
      this.timeoutInMillis=(int)((TimeSpan)oTimeout).getMillis();
    else
      this.timeoutInMillis = (int)(Caster.toDoubleValue(oTimeout)*1000D);
    //print.out(Caster.toString(timeoutInMillis));
  }
  public void setTimeout(double timeout) {
    this.timeoutInMillis = (int)(timeout*1000D);
  }

  /** set the value type
  *  readOnly or Exclusive. Specifies the type of lock: read-only or exclusive. Default is Exclusive.
  *   A read-only lock allows more than one request to read shared data. An exclusive lock allows only one
  *   request to read or write to shared data.
  * @param type value to set
   * @throws ApplicationException
  **/
  public void setType(String type) throws ApplicationException {
    type=type.toLowerCase().trim();
       
    if(type.equals("exclusive")) {
        this.type=LockManager.TYPE_EXCLUSIVE;
    }
    else if(type.startsWith("read")){
        this.type=LockManager.TYPE_READONLY;
    }
    else
      throw new ApplicationException("invalid value ["+type+"] for attribute [type] from tag [lock]",
          "valid values are [exclusive,read-only]");
  }

  /** set the value scope
  *  Specifies the scope as one of the following: Application, Server, or Session. This attribute is mutually
  *   exclusive with the name attribute.
  * @param scope value to set
   * @throws ApplicationException
  **/
  public void setScope(String scope) throws ApplicationException {
    scope=scope.toLowerCase().trim();
   
    if(scope.equals("server"))this.scope=SCOPE_SERVER;
    else if(scope.equals("application"))this.scope=SCOPE_APPLICATION;
    else if(scope.equals("session"))this.scope=SCOPE_SESSION;
    else if(scope.equals("request"))this.scope=SCOPE_REQUEST;
    else
      throw new ApplicationException("invalid value ["+scope+"] for attribute [scope] from tag [lock]",
          "valid values are [server,application,session]");
  }

  /** set the value throwontimeout
  *  Yes or No. Specifies how timeout conditions are handled. If the value is Yes, an exception is
  *   generated to provide notification of the timeout. If the value is No, execution continues past the
  *    cfclock tag. Default is Yes.
  * @param throwontimeout value to set
  **/
  public void setThrowontimeout(boolean throwontimeout) {
    this.throwontimeout = throwontimeout;
  }

  /** set the value name
  * @param name value to set
   * @throws ApplicationException
  **/
  public void setName(String name) throws ApplicationException {
    if(name==null) return;
    this.name = name.trim();
    if(name.length()==0)throw new ApplicationException("invalid attribute definition","attribute [name] can't be a empty string");
  }

  @Override
  public int doStartTag() throws PageException {
    //if(timeoutInMillis==0)timeoutInMillis=30000;
    //print.out("doStartTag");
      manager=pageContext.getConfig().getLockManager();
        // check attributes
      if(name!=null && scope!=SCOPE_NONE) {
          throw new LockException(
                  LockException.OPERATION_CREATE,
                  this.name,
                  "invalid attribute combination",
                    "attribute [name] and [scope] can't be used together");
        }
      if(name==null && scope==SCOPE_NONE)    {
        name="id-"+id;
        }
       
      String lockType = null;
      if(name==null) {
        String cid=pageContext.getConfig().getId();
          // Session
          if(scope==SCOPE_REQUEST){
              lockType="request";
              name="__request_"+cid+"__"+ ((RequestImpl)pageContext.requestScope())._getId();
          }
          // Session
          else if(scope==SCOPE_SESSION){
              lockType="session";
              name="__session_"+cid+"__"+ pageContext.sessionScope()._getId();
          }
          // Application
          else if(scope==SCOPE_APPLICATION){
              lockType="application";
              name="__application_"+cid+"__"+((ApplicationImpl)pageContext.applicationScope())._getId();
          }
          // Server
          else if(scope==SCOPE_SERVER){
              lockType="server";
              name="__server_"+((ServerImpl)pageContext.serverScope())._getId();
          }
      }
      Struct cflock=new StructImpl();
      cflock.set("succeeded",Boolean.TRUE);
      cflock.set("errortext","");
      pageContext.variablesScope().set("cflock",cflock);
        start=System.nanoTime();
        try {
        ((PageContextImpl)pageContext).setActiveLock(new ActiveLock(type,name,timeoutInMillis)); // this has to be first, otherwise LockTimeoutException has nothing to release
        data = manager.lock(type,name,timeoutInMillis,pageContext.getId());
    }
    catch (LockTimeoutException e) {
      LockManagerImpl mi = (LockManagerImpl)manager;
        Boolean hasReadLock = mi.isReadLocked(name);
        Boolean hasWriteLock = mi.isWriteLocked(name);
        String msg = LockTimeoutExceptionImpl.createMessage(type, name, lockType, timeoutInMillis, hasReadLock, hasWriteLock);
       
        _release(pageContext,System.nanoTime()-start);
        name=null;
       
        cflock.set("succeeded",Boolean.FALSE);
        cflock.set("errortext",msg);

      if(throwontimeout) throw new LockException(
                  LockException.OPERATION_TIMEOUT,
                  this.name,
                  msg);
     
      return SKIP_BODY;
    }
    catch (InterruptedException e) {
      _release(pageContext,System.nanoTime()-start);
        cflock.set("succeeded",Boolean.FALSE);
        cflock.set("errortext",e.getMessage());
       
        if(throwontimeout) throw Caster.toPageException(e);
     
      return SKIP_BODY;
       
       
    }
   
    return EVAL_BODY_INCLUDE;
  }
 
  private void _release(PageContext pc, long exe) {
    ActiveLock al = ((PageContextImpl)pc).releaseActiveLock();
      // listener
    ((ConfigWebImpl)pc.getConfig()).getActionMonitorCollector()
      .log(pageContext, "lock", "Lock", exe, al.name+":"+al.timeoutInMillis);
   
  }


  @Override
  public void doFinally() {
    _release(pageContext,System.nanoTime()-start);
      if(name!=null)manager.unlock(data);
  }
 
 
}
TOP

Related Classes of railo.runtime.tag.Lock

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.