Package railo.runtime.tag

Source Code of railo.runtime.tag.CFTag

package railo.runtime.tag;

import java.io.IOException;
import java.util.Iterator;
import java.util.Map.Entry;

import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.tagext.Tag;

import railo.commons.lang.StringUtil;
import railo.runtime.Component;
import railo.runtime.Mapping;
import railo.runtime.PageContext;
import railo.runtime.PageContextImpl;
import railo.runtime.PageSource;
import railo.runtime.component.ComponentLoader;
import railo.runtime.component.Member;
import railo.runtime.config.ConfigWebImpl;
import railo.runtime.customtag.CustomTagUtil;
import railo.runtime.customtag.InitFile;
import railo.runtime.engine.ThreadLocalPageContext;
import railo.runtime.exp.ApplicationException;
import railo.runtime.exp.CasterException;
import railo.runtime.exp.ExpressionException;
import railo.runtime.exp.PageException;
import railo.runtime.exp.PageRuntimeException;
import railo.runtime.exp.PageServletException;
import railo.runtime.ext.tag.AppendixTag;
import railo.runtime.ext.tag.BodyTagTryCatchFinallyImpl;
import railo.runtime.ext.tag.DynamicAttributes;
import railo.runtime.op.Caster;
import railo.runtime.op.Decision;
import railo.runtime.type.Collection;
import railo.runtime.type.Collection.Key;
import railo.runtime.type.KeyImpl;
import railo.runtime.type.Struct;
import railo.runtime.type.StructImpl;
import railo.runtime.type.scope.Caller;
import railo.runtime.type.scope.CallerImpl;
import railo.runtime.type.scope.Undefined;
import railo.runtime.type.scope.Variables;
import railo.runtime.type.scope.VariablesImpl;
import railo.runtime.type.util.ArrayUtil;
import railo.runtime.type.util.ComponentUtil;
import railo.runtime.type.util.KeyConstants;
import railo.runtime.type.util.ListUtil;
import railo.runtime.type.util.Type;
import railo.runtime.util.QueryStack;
import railo.runtime.util.QueryStackImpl;
import railo.transformer.library.tag.TagLibTag;
import railo.transformer.library.tag.TagLibTagAttr;


/**
* Creates a CFML Custom Tag
**/
public class CFTag extends BodyTagTryCatchFinallyImpl implements DynamicAttributes,AppendixTag {

  private static Collection.Key GENERATED_CONTENT=KeyImpl.intern("GENERATEDCONTENT");
  private static Collection.Key EXECUTION_MODE=KeyImpl.intern("EXECUTIONMODE");     
  private static Collection.Key EXECUTE_BODY=KeyImpl.intern("EXECUTEBODY");
  private static Collection.Key PARENT=KeyImpl.intern("PARENT");
  private static Collection.Key CFCATCH=KeyConstants._CFCATCH;
  private static Collection.Key SOURCE=KeyImpl.intern("SOURCE");
 
  private static final Collection.Key ON_ERROR = KeyImpl.intern("onError");
  private static final Collection.Key ON_FINALLY = KeyImpl.intern("onFinally");
  private static final Collection.Key ON_START_TAG = KeyImpl.intern("onStartTag");
  private static final Collection.Key ON_END_TAG = KeyImpl.intern("onEndTag");

  private static final Collection.Key ATTRIBUTE_TYPE = KeyImpl.intern("attributetype");
  private static final Collection.Key RT_EXPR_VALUE = KeyImpl.intern("rtexprvalue");
  private static final String MARKER = "2w12801";
 
    /**
     * Field <code>attributesScope</code>
     */
    // new scopes
    protected StructImpl attributesScope;
    private Caller callerScope;
    private StructImpl thistagScope;

    private Variables ctVariablesScope;

    private boolean hasBody;

    /**
     * Field <code>filename</code>
     */
    //protected String filename;

    /**
     * Field <code>source</code>
     */
    protected InitFile source;
    private String appendix;
  //private boolean doCustomTagDeepSearch;
 
  private Component cfc;
  private boolean isEndTag;
 
 
 
    /**
    * constructor for the tag class
    **/
    public CFTag() {
      attributesScope = new StructImpl();
        callerScope = new CallerImpl();
        //thistagScope = new StructImpl();
    }

    @Override
    public void setDynamicAttribute(String uri, String name, Object value) {
      TagUtil.setDynamicAttribute(attributesScope,KeyImpl.init(name),value,TagUtil.ORIGINAL_CASE);
    }

    @Override
    public void setDynamicAttribute(String uri, Collection.Key name, Object value) {
      TagUtil.setDynamicAttribute(attributesScope,name,value,TagUtil.ORIGINAL_CASE);
    }

    @Override
    public void release()   {
        super.release();

        hasBody=false;
        //filename=null;     

        attributesScope=new StructImpl();//.clear();
        callerScope = new CallerImpl();
        if(thistagScope!=null)thistagScope=null;
        if(ctVariablesScope!=null)ctVariablesScope=null
       

        isEndTag=false;    
       
        //cfc=null;
        source=null;
    }

    /**
     * sets the appendix of the class
     * @param appendix
     */
    public void setAppendix(String appendix) {
        this.appendix=appendix;
        //filename = appendix+'.'+pageContext.getConfig().getCFMLExtension();
    }

    @Override
    public int doStartTag() throws PageException    {
      PageContextImpl pci=(PageContextImpl) pageContext;
    boolean old=pci.useSpecialMappings(true);
    try{
      initFile();
        callerScope.initialize(pageContext);
          if(source.isCFC())return cfcStartTag();
          return cfmlStartTag()
    }
    finally{
      pci.useSpecialMappings(old);
    }
    }

    @Override
    public int doEndTag()   {
      PageContextImpl pci=(PageContextImpl) pageContext;
    boolean old=pci.useSpecialMappings(true);
    try{
      if(source.isCFC())_doCFCFinally();
          return EVAL_PAGE;
    }
    finally{
      pci.useSpecialMappings(old);
    }
    }

    @Override
    public void doInitBody()    {
       
    }

    @Override
    public int doAfterBody() throws PageException   {
      if(source.isCFC())return cfcEndTag();
        return cfmlEndTag();
    }
   

  @Override
    public void doCatch(Throwable t) throws Throwable {
      if(source.isCFC()){
        String source=isEndTag?"end":"body";
        isEndTag=false;
        _doCFCCatch(t,source);
      }
      else super.doCatch(t);
  }
   
    void initFile() throws PageException {
        source=initFile(pageContext);
    }

    public InitFile initFile(PageContext pageContext) throws PageException {
      return CustomTagUtil.loadInitFile(pageContext, appendix);
    }
   
  private int cfmlStartTag() throws PageException {
    callerScope.initialize(pageContext);
       
    // thistag
    if(thistagScope==null)thistagScope=new StructImpl(StructImpl.TYPE_LINKED);
        thistagScope.set(GENERATED_CONTENT,"");
        thistagScope.set(EXECUTION_MODE,"start");     
        thistagScope.set(EXECUTE_BODY,Boolean.TRUE);
        thistagScope.set(KeyConstants._HASENDTAG,Caster.toBoolean(hasBody));
       
   
    ctVariablesScope=new VariablesImpl();
        ctVariablesScope.setEL(KeyConstants._ATTRIBUTES,attributesScope);
        ctVariablesScope.setEL(KeyConstants._CALLER,callerScope);
        ctVariablesScope.setEL(KeyConstants._THISTAG,thistagScope);
       
       
        // include
        doInclude();
       
        return Caster.toBooleanValue(thistagScope.get(EXECUTE_BODY))?EVAL_BODY_BUFFERED:SKIP_BODY;
    }
 
    private int cfmlEndTag() throws PageException {
        // thistag    
      String genConBefore = bodyContent.getString();
      thistagScope.set(GENERATED_CONTENT,genConBefore);
        thistagScope.set(EXECUTION_MODE,"end");
        thistagScope.set(EXECUTE_BODY,Boolean.FALSE);
        writeEL(bodyContent, MARKER);
       
        // include
        try{
          doInclude();
        }
        catch(Throwable t){
          writeOut(genConBefore);
          throw Caster.toPageException(t);
        }
       
        writeOut(genConBefore);

        return Caster.toBooleanValue(thistagScope.get(EXECUTE_BODY))?EVAL_BODY_BUFFERED:SKIP_BODY;
    }

   

  private void writeOut(String genConBefore) throws PageException {
    String output = bodyContent.getString();
    bodyContent.clearBody();
      String genConAfter = Caster.toString(thistagScope.get(GENERATED_CONTENT));
     
      if(genConBefore!=genConAfter){
          if(output.startsWith(genConBefore+MARKER)){
          output=output.substring((genConBefore+MARKER).length());
        }
        output=genConAfter+output;
      }
      else {
        if(output.startsWith(genConBefore+MARKER)){
          output=output.substring((genConBefore+MARKER).length());
          output=genConBefore+output;
        }
      }
     
     
      writeEL(bodyContent.getEnclosingWriter(),output);
  }

  private void writeEL(JspWriter writer, String str) throws PageException {
    try {
      writer.write(str);
    } catch (IOException e) {
      throw Caster.toPageException(e);
    }
  }

  void doInclude() throws PageException {
        Variables var=pageContext.variablesScope();
        pageContext.setVariablesScope(ctVariablesScope);
       
       
        QueryStack cs=null;
        Undefined undefined=pageContext.undefinedScope();
        int oldMode=undefined.setMode(Undefined.MODE_NO_LOCAL_AND_ARGUMENTS);
        if(oldMode!=Undefined.MODE_NO_LOCAL_AND_ARGUMENTS)
          callerScope.setScope(var,pageContext.localScope(),pageContext.argumentsScope(),true);
        else
          callerScope.setScope(var,null,null,false);
       
        if(pageContext.getConfig().allowImplicidQueryCall()) {
            cs=undefined.getQueryStack();
            undefined.setQueryStack(new QueryStackImpl());
        }
           
        try {
            pageContext.doInclude(new PageSource[]{source.getPageSource()},false);
        }
        catch (Throwable t) {
            throw Caster.toPageException(t);
        }
        finally {
            undefined.setMode(oldMode);
            //varScopeData=variablesScope.getMap();
            pageContext.setVariablesScope(var);
            if(pageContext.getConfig().allowImplicidQueryCall()) {
                undefined.setQueryStack(cs);
            }
        }
   
    }
   
   
    // CFC
   
    private int cfcStartTag() throws PageException {
     
      callerScope.initialize(pageContext);
        try {
      cfc = ComponentLoader.loadComponent(pageContext,null,source.getPageSource(), source.getFilename().substring(0,source.getFilename().length()-(pageContext.getConfig().getCFCExtension().length()+1)), false,true);
    }
    catch (PageException e) {
      Mapping m = source.getPageSource().getMapping();
      ConfigWebImpl c=(ConfigWebImpl) pageContext.getConfig();
      if(m==c.getTagMapping()) m=c.getServerTagMapping();
      else m=null;
      // is te page source from a tag mapping, so perhaps it was moved from server to web context
      if(m!=null){
        PageSource ps = m.getPageSource(source.getFilename());
        try {
          cfc = ComponentLoader.loadComponent(pageContext,null,ps, source.getFilename().substring(0,source.getFilename().length()-(pageContext.getConfig().getCFCExtension().length()+1)), false,true);
        }
        catch (PageException e1) {
          throw e;
        }
       
      }
    }
       
        validateAttributes(cfc,attributesScope,StringUtil.ucFirst(ListUtil.last(source.getPageSource().getComponentName(),'.')));
       
        boolean exeBody = false;
        try  {
      Object rtn=Boolean.TRUE;
      if(cfc.contains(pageContext, KeyConstants._init)){
            Tag parent=getParent();
            while(parent!=null && !(parent instanceof CFTag && ((CFTag)parent).isCFCBasedCustomTag())) {
            parent=parent.getParent();
          }
        Struct args=new StructImpl(StructImpl.TYPE_LINKED);
        args.set(KeyConstants._HASENDTAG, Caster.toBoolean(hasBody));
          if(parent instanceof CFTag) {
            args.set(PARENT, ((CFTag)parent).getComponent());
          }
            rtn=cfc.callWithNamedValues(pageContext, KeyConstants._init, args);
          }
     
          if(cfc.contains(pageContext, ON_START_TAG)){
            Struct args=new StructImpl();
            args.set(KeyConstants._ATTRIBUTES, attributesScope);
            setCaller(pageContext,args);
           
            rtn=cfc.callWithNamedValues(pageContext, ON_START_TAG, args)
        }
          exeBody=Caster.toBooleanValue(rtn,true);
        }
        catch(Throwable t){
          _doCFCCatch(t,"start");
        }
        return exeBody?EVAL_BODY_BUFFERED:SKIP_BODY;
    }
   
    private void setCaller(PageContext pageContext, Struct args) throws PageException {
      callerScope.initialize(pageContext);
      boolean checkAgs=pageContext.undefinedScope().getCheckArguments();
      if(checkAgs)
          callerScope.setScope(pageContext.variablesScope(),pageContext.localScope(),pageContext.argumentsScope(),true);
        else
          callerScope.setScope(pageContext.variablesScope(),null,null,false);
       
     
      args.set(KeyConstants._CALLER, callerScope);
     
     
     
      //args.set(KeyConstants._CALLER, Duplicator.duplicate(pageContext.undefinedScope(),false));
  }

  private static void validateAttributes(Component cfc,StructImpl attributesScope,String tagName) throws ApplicationException, ExpressionException {
   
    TagLibTag tag=getAttributeRequirments(cfc,false);
    if(tag==null) return;
   
    if(tag.getAttributeType()==TagLibTag.ATTRIBUTE_TYPE_FIXED || tag.getAttributeType()==TagLibTag.ATTRIBUTE_TYPE_MIXED){
      Iterator<Entry<String, TagLibTagAttr>> it = tag.getAttributes().entrySet().iterator();
      int count=0;
      Collection.Key key;
      TagLibTagAttr attr;
      Object value;
      Entry<String, TagLibTagAttr> entry;
      // check existing attributes
      while(it.hasNext()){
        entry = it.next();
        count++;
        key=KeyImpl.toKey(entry.getKey(),null);
        attr=entry.getValue();
        value=attributesScope.get(key,null);
        if(value==null){
          if(attr.getDefaultValue()!=null){
            value=attr.getDefaultValue();
            attributesScope.setEL(key, value);
          }
          else if(attr.isRequired())
            throw new ApplicationException("attribute ["+key.getString()+"] is required for tag ["+tagName+"]");
        }
        if(value!=null) {
          if(!Decision.isCastableTo(attr.getType(),value,true,true,-1))
            throw new CasterException(createMessage(attr.getType(), value));
       
        }
      }
     
      // check if there are attributes not supported
      if(tag.getAttributeType()==TagLibTag.ATTRIBUTE_TYPE_FIXED && count<attributesScope.size()){
        Collection.Key[] keys = attributesScope.keys();
        for(int i=0;i<keys.length;i++){
          if(tag.getAttribute(keys[i].getLowerString())==null)
            throw new ApplicationException("attribute ["+keys[i].getString()+"] is not supported for tag ["+tagName+"]");
        }
       
         //Attribute susi is not allowed for tag cfmail
      }
    }
  }
   
    private static String createMessage(String type, Object value) {
      if(value instanceof String) return "can't cast String ["+value+"] to a value of type ["+type+"]";
      else if(value!=null) return "can't cast Object type ["+Type.getName(value)+"] to a value of type ["+type+"]";
    else return "can't cast Null value to value of type ["+type+"]";

    }
   

  private static TagLibTag getAttributeRequirments(Component cfc, boolean runtime) throws ExpressionException {
   
    Struct meta=null;
      //try {
        //meta = Caster.toStruct(cfc.get(Component.ACCESS_PRIVATE, METADATA),null,false);
        Member mem = ComponentUtil.toComponentAccess(cfc).getMember(Component.ACCESS_PRIVATE, KeyConstants._metadata,true,false);
        if(mem!=null)meta = Caster.toStruct(mem.getValue(),null,false);
    //}catch (PageException e) {e.printStackTrace();}
      if(meta==null) return null;
     
      TagLibTag tag=new TagLibTag(null);
    // TAG

      // type     
      String type=Caster.toString(meta.get(ATTRIBUTE_TYPE,"dynamic"),"dynamic");
     
      if("fixed".equalsIgnoreCase(type))tag.setAttributeType(TagLibTag.ATTRIBUTE_TYPE_FIXED);
      //else if("mixed".equalsIgnoreCase(type))tag.setAttributeType(TagLibTag.ATTRIBUTE_TYPE_MIXED);
      //else if("noname".equalsIgnoreCase(type))tag.setAttributeType(TagLibTag.ATTRIBUTE_TYPE_NONAME);
      else tag.setAttributeType(TagLibTag.ATTRIBUTE_TYPE_DYNAMIC);
     
      if(!runtime){
        // hint
        String hint=Caster.toString(meta.get(KeyConstants._hint,null),null);
        if(!StringUtil.isEmpty(hint))tag.setDescription(hint);
      }
     
    // ATTRIBUTES
      Struct attributes=Caster.toStruct(meta.get(KeyConstants._ATTRIBUTES,null),null,false);
      if(attributes!=null) {
        Iterator<Entry<Key, Object>> it = attributes.entryIterator();
        //Iterator it = attributes.entrySet().iterator();
        Entry<Key, Object> entry;
        TagLibTagAttr attr;
        Struct sct;
        String name;
        Object defaultValue;
        while(it.hasNext()){
          entry=it.next();
          name=Caster.toString(entry.getKey(),null);
          if(StringUtil.isEmpty(name)) continue;
          attr=new TagLibTagAttr(tag);
          attr.setName(name);
         
          sct=Caster.toStruct(entry.getValue(),null,false);
          if(sct!=null){
            attr.setRequired(Caster.toBooleanValue(sct.get(KeyConstants._required,Boolean.FALSE),false));
            attr.setType(Caster.toString(sct.get(KeyConstants._type,"any"),"any"));
           
            defaultValue= sct.get(KeyConstants._default,null);
            if(defaultValue!=null)attr.setDefaultValue(defaultValue);
           
           
            if(!runtime){
              attr.setDescription(Caster.toString(sct.get(KeyConstants._hint,null),null));
              attr.setRtexpr(Caster.toBooleanValue(sct.get(RT_EXPR_VALUE,Boolean.TRUE),true));
            }
          }
          tag.setAttribute(attr);
         
        }
      }
      return tag;
  }

  private int cfcEndTag() throws PageException {
       
      boolean exeAgain = false;
        try{
        String output=null;
        Object rtn=Boolean.FALSE;
         
       
        if(cfc.contains(pageContext, ON_END_TAG)){
          try {
              output=bodyContent.getString();
                bodyContent.clearBody();
                //rtn=cfc.call(pageContext, ON_END_TAG, new Object[]{attributesScope,pageContext.variablesScope(),output});
               
                Struct args=new StructImpl(StructImpl.TYPE_LINKED);
              args.set(KeyConstants._ATTRIBUTES, attributesScope);
              setCaller(pageContext, args);
              args.set(GENERATED_CONTENT, output);
              rtn=cfc.callWithNamedValues(pageContext, ON_END_TAG, args)
         
               
               
            }
            finally  {
              writeEnclosingWriter();
            }
          }
        else writeEnclosingWriter();
       
          exeAgain= Caster.toBooleanValue(rtn,false);
      }
        catch(Throwable t){
          isEndTag=true;
          throw Caster.toPageException(t);
        }
        return exeAgain?EVAL_BODY_BUFFERED:SKIP_BODY;
     
    }
   
    public void _doCFCCatch(Throwable t, String source) throws PageException {
      writeEnclosingWriter();
     
      // remove PageServletException wrap
      if(t instanceof PageServletException) {
        PageServletException pse=(PageServletException)t;
        t=pse.getPageException();
    }
     
      // abort
      try {
      if(railo.runtime.exp.Abort.isAbort(t)){
        if(bodyContent!=null){
          bodyContent.writeOut(bodyContent.getEnclosingWriter());
          bodyContent.clearBuffer();
        }
        throw Caster.toPageException(t);
      }
    }
    catch(IOException ioe){
      throw Caster.toPageException(ioe);
    }
     
     
     
      try {
      if(cfc.contains(pageContext, ON_ERROR)){
            PageException pe = Caster.toPageException(t);
            //Object rtn=cfc.call(pageContext, ON_ERROR, new Object[]{pe.getCatchBlock(pageContext),source});
         
            Struct args=new StructImpl(StructImpl.TYPE_LINKED);
            args.set(CFCATCH, pe.getCatchBlock(ThreadLocalPageContext.getConfig(pageContext)));
            args.set(SOURCE, source);
            Object rtn=cfc.callWithNamedValues(pageContext, ON_ERROR, args)
       
            if(Caster.toBooleanValue(rtn,false))
          throw t;
          }
      else throw t;
      }
      catch(Throwable th) {
        writeEnclosingWriter();
        _doCFCFinally();
        throw Caster.toPageException(th);
      }
      writeEnclosingWriter();
  }
   
    private void _doCFCFinally() {
    if(cfc.contains(pageContext, ON_FINALLY)){
      try {
        cfc.call(pageContext, ON_FINALLY, ArrayUtil.OBJECT_EMPTY);
      }
      catch (PageException pe) {
        throw new PageRuntimeException(pe);
      }
      finally{
        writeEnclosingWriter();
      }
        }
  }
   
   
    private void writeEnclosingWriter()  {
      if(bodyContent!=null){
      try {
        String output = bodyContent.getString();
        bodyContent.clearBody();
              bodyContent.getEnclosingWriter().write(output);   
          }
      catch (IOException e) {
            //throw Caster.toPageException(e);
          }
      }
  }
   
   

    /**
     * sets if tag has a body or not
     * @param hasBody
     */
    public void hasBody(boolean hasBody) {
      this.hasBody=hasBody;
    }

    /**
     * @return Returns the appendix.
     */
    public String getAppendix() {
        return appendix;
    }

    /**
     * @return return thistag
     */
    public Struct getThis() {
      if(isCFCBasedCustomTag()){
        return cfc;
      }
        return thistagScope;
    }
   
    /**
     * @return return thistag
     */
    public Struct getCallerScope() {
        return callerScope;
    }
   
    /**
     * @return return thistag
     */
    public Struct getAttributesScope() {
        return attributesScope;
    }

  /**
   * @return the ctVariablesScope
   */
  public Struct getVariablesScope() {
    if(isCFCBasedCustomTag())  {
      return cfc.getComponentScope();
    }
    return ctVariablesScope;
  }
 
    /**
   * @return the cfc
   */
  public Component getComponent() {
    return cfc;
  }
 
  public boolean isCFCBasedCustomTag() {
    return getSource().isCFC();
  }
 
  private InitFile getSource() {
    if(source==null){
      try {
        source=initFile(pageContext);
      } catch (PageException e) {
        e.printStackTrace();
      }
    }
    return source;
  }

  /*class InitFile {
    PageSource ps;
    String filename;
    boolean isCFC;

    public InitFile(PageSource ps,String filename,boolean isCFC){
      this.ps=ps;
      this.filename=filename;
      this.isCFC=isCFC;
    }
  }*/
 
 
}
TOP

Related Classes of railo.runtime.tag.CFTag

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.